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>
diff --git a/go/ssa/builder.go b/go/ssa/builder.go
index 1460d48..4bab92d 100644
--- a/go/ssa/builder.go
+++ b/go/ssa/builder.go
@@ -347,7 +347,7 @@
if v == nil {
v = fn.lookup(obj, escaping)
}
- return &address{addr: v, expr: e}
+ return &address{addr: v, pos: e.Pos(), expr: e}
case *ast.CompositeLit:
t := deref(fn.Pkg.typeOf(e))
@@ -359,7 +359,7 @@
}
v.Comment = "complit"
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:
return b.addr(fn, e.X, escaping)
@@ -378,6 +378,7 @@
last := len(sel.Index()) - 1
return &address{
addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel),
+ pos: e.Sel.Pos(),
expr: e.Sel,
}
@@ -410,10 +411,10 @@
}
v.setPos(e.Lbrack)
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:
- 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))
@@ -891,7 +892,7 @@
}
iaddr.setType(types.NewPointer(vt))
fn.emit(iaddr)
- emitStore(fn, iaddr, arg)
+ emitStore(fn, iaddr, arg, arg.Pos())
}
s := &Slice{X: a}
s.setType(st)
@@ -1044,17 +1045,19 @@
switch t := typ.Underlying().(type) {
case *types.Struct:
if !isZero && len(e.Elts) != t.NumFields() {
- emitMemClear(fn, addr)
+ emitMemClear(fn, addr, e.Lbrace)
isZero = true
}
for i, e := range e.Elts {
fieldIndex := i
+ pos := e.Pos()
if kv, ok := e.(*ast.KeyValueExpr); ok {
fname := kv.Key.(*ast.Ident).Name
for i, n := 0, t.NumFields(); i < n; i++ {
sf := t.Field(i)
if sf.Name() == fname {
fieldIndex = i
+ pos = kv.Colon
e = kv.Value
break
}
@@ -1067,7 +1070,7 @@
}
faddr.setType(types.NewPointer(sf.Type()))
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:
@@ -1086,7 +1089,7 @@
}
if !isZero && int64(len(e.Elts)) != at.Len() {
- emitMemClear(fn, array)
+ emitMemClear(fn, array, e.Lbrace)
isZero = true
}
@@ -1108,20 +1111,20 @@
}
iaddr.setType(types.NewPointer(at.Elem()))
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
s := &Slice{X: array}
s.setPos(e.Lbrace)
s.setType(typ)
- emitStore(fn, addr, fn.emit(s))
+ emitStore(fn, addr, fn.emit(s), e.Lbrace)
}
case *types.Map:
m := &MakeMap{Reserve: intConst(int64(len(e.Elts)))}
m.setPos(e.Lbrace)
m.setType(typ)
- emitStore(fn, addr, fn.emit(m))
+ emitStore(fn, addr, fn.emit(m), e.Lbrace)
for _, e := range e.Elts {
e := e.(*ast.KeyValueExpr)
loc := &element{
@@ -1337,7 +1340,7 @@
// In a single-type case, y has that type.
// In multi-type cases, 'case nil' and default,
// 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{
tail: fn.targets,
@@ -1588,8 +1591,9 @@
// rangeIndexed emits to fn the header for an integer-indexed loop
// over array, *array or slice value x.
// 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)
// index = -1
@@ -1623,7 +1627,7 @@
}
index := fn.addLocal(tInt, token.NoPos)
- emitStore(fn, index, intConst(-1))
+ emitStore(fn, index, intConst(-1), pos)
loop = fn.newBasicBlock("rangeindex.loop")
emitJump(fn, loop)
@@ -1635,7 +1639,7 @@
Y: vOne,
}
incr.setType(tInt)
- emitStore(fn, index, fn.emit(incr))
+ emitStore(fn, index, fn.emit(incr), pos)
body := fn.newBasicBlock("rangeindex.body")
done = fn.newBasicBlock("rangeindex.done")
@@ -1814,10 +1818,10 @@
var loop, done *BasicBlock
switch rt := x.Type().Underlying().(type) {
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:
- 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
k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For)
@@ -1955,7 +1959,7 @@
// Function has named result parameters (NRPs).
// Perform parallel assignment of return operands to NRPs.
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
@@ -2206,7 +2210,7 @@
done = init.newBasicBlock("init.done")
emitIf(init, emitLoad(init, initguard), done, doinit)
init.currentBlock = doinit
- emitStore(init, initguard, vTrue)
+ emitStore(init, initguard, vTrue, token.NoPos)
// Call the init() function of each package we import.
for _, pkg := range p.info.Pkg.Imports() {
@@ -2234,7 +2238,7 @@
// 1:1 initialization: var x, y = a(), b()
var lval lvalue
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 {
lval = blank{}
}
@@ -2246,7 +2250,7 @@
if v.Name() == "_" {
continue
}
- emitStore(init, p.values[v].(*Global), emitExtract(init, tuple, i))
+ emitStore(init, p.values[v].(*Global), emitExtract(init, tuple, i), v.Pos())
}
}
}
diff --git a/go/ssa/emit.go b/go/ssa/emit.go
index 84246c6..261d6e0 100644
--- a/go/ssa/emit.go
+++ b/go/ssa/emit.go
@@ -246,10 +246,11 @@
// emitStore emits to f an instruction to store value val at location
// 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{
Addr: addr,
Val: emitConv(f, val, deref(addr.Type())),
+ pos: pos,
}
f.emit(s)
return s
@@ -430,9 +431,9 @@
}
// 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.
- 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
diff --git a/go/ssa/lvalue.go b/go/ssa/lvalue.go
index e58bc24..8342645 100644
--- a/go/ssa/lvalue.go
+++ b/go/ssa/lvalue.go
@@ -27,20 +27,19 @@
// An address is an lvalue represented by a true pointer.
type address struct {
- addr Value
- starPos token.Pos // source position, if from explicit *addr
- expr ast.Expr // source syntax [debug mode]
+ addr Value
+ pos token.Pos // source position
+ expr ast.Expr // source syntax [debug mode]
}
func (a *address) load(fn *Function) Value {
load := emitLoad(fn, a.addr)
- load.pos = a.starPos
+ load.pos = a.pos
return load
}
func (a *address) store(fn *Function, v Value) {
- store := emitStore(fn, a.addr, v)
- store.pos = a.starPos
+ store := emitStore(fn, a.addr, v, a.pos)
if a.expr != nil {
// store.Val is v, converted for assignability.
emitDebugRef(fn, a.expr, store.Val, false)
diff --git a/go/ssa/ssa.go b/go/ssa/ssa.go
index bc5e9da..406611e 100644
--- a/go/ssa/ssa.go
+++ b/go/ssa/ssa.go
@@ -564,8 +564,12 @@
// and a boolean indicating the success of the receive. The
// components of the tuple are accessed using Extract.
//
-// Pos() returns the ast.UnaryExpr.OpPos or ast.RangeStmt.TokPos (for
-// ranging over a channel), if explicit in the source.
+// Pos() returns the ast.UnaryExpr.OpPos, 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:
// t0 = *x
@@ -1162,7 +1166,10 @@
// The Store instruction stores Val at address Addr.
// 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:
// *x = y
diff --git a/go/ssa/testmain.go b/go/ssa/testmain.go
index 422c7db..ae9ec1c 100644
--- a/go/ssa/testmain.go
+++ b/go/ssa/testmain.go
@@ -247,7 +247,7 @@
pname := fn.emit(fa)
// Emit: *pname = "testfunc"
- emitStore(fn, pname, stringConst(testfunc.Name()))
+ emitStore(fn, pname, stringConst(testfunc.Name()), token.NoPos)
// Emit: pfunc = &pitem.F
fa = &FieldAddr{X: pitem, Field: 1} // .F
@@ -255,7 +255,7 @@
pfunc := fn.emit(fa)
// Emit: *pfunc = testfunc
- emitStore(fn, pfunc, testfunc)
+ emitStore(fn, pfunc, testfunc, token.NoPos)
}
// Emit: slice array[:]