diff options
author | Keith Randall <khr@golang.org> | 2015-10-22 14:22:38 -0700 |
---|---|---|
committer | Keith Randall <khr@golang.org> | 2015-10-28 17:00:31 +0000 |
commit | c24681ae2e1c96bd67c149cffa8f5ed394e68453 (patch) | |
tree | 901661939332bae3a55be8102da790778f1161e8 /src/cmd/compile/internal/ssa/stackalloc.go | |
parent | d43f2e37edf4115e31a0c9218d87182d0aa1c4f0 (diff) | |
download | go-c24681ae2e1c96bd67c149cffa8f5ed394e68453.tar.gz go-c24681ae2e1c96bd67c149cffa8f5ed394e68453.zip |
[dev.ssa] cmd/compile: remember names of values
For debugging, spill values to named variables instead of autotmp_
variables if possible. We do this by keeping a name -> value map
for each function, keep it up-to-date during deadcode elim, and use
it to override spill decisions in stackalloc.
It might even make stack frames a bit smaller, as it makes it easy
to identify a set of spills which are likely not to interfere.
This just works for one-word variables for now. Strings/slices
will be a separate CL.
Change-Id: Ie89eba8cab16bcd41b311c479ec46dd7e64cdb67
Reviewed-on: https://go-review.googlesource.com/16336
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Diffstat (limited to 'src/cmd/compile/internal/ssa/stackalloc.go')
-rw-r--r-- | src/cmd/compile/internal/ssa/stackalloc.go | 63 |
1 files changed, 58 insertions, 5 deletions
diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 17d1f66cea..793162a797 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -36,7 +36,8 @@ func stackalloc(f *Func) { case v.Op == OpStoreReg, v.isStackPhi(): s.remove(v.ID) for _, id := range s.contents() { - if v.Type == types[id] { + if v.Type.Equal(types[id]) { + // Only need interferences between equivalent types. interfere[v.ID] = append(interfere[v.ID], id) interfere[id] = append(interfere[id], v.ID) } @@ -47,6 +48,18 @@ func stackalloc(f *Func) { } } + // Build map from values to their names, if any. + // A value may be associated with more than one name (e.g. after + // the assignment i=j). This step picks one name per value arbitrarily. + names := make([]GCNode, f.NumValues()) + for _, name := range f.Names { + // Note: not "range f.NamedValues" above, because + // that would be nondeterministic. + for _, v := range f.NamedValues[name] { + names[v.ID] = name + } + } + // Figure out which StoreReg ops are phi args. We don't pick slots for // phi args because a stack phi and its args must all use the same stack slot. phiArg := make([]bool, f.NumValues()) @@ -67,6 +80,7 @@ func stackalloc(f *Func) { // Each time we assign a stack slot to a value v, we remember // the slot we used via an index into locations[v.Type]. + // TODO: share slots among equivalent types. slots := make([]int, f.NumValues()) for i := f.NumValues() - 1; i >= 0; i-- { slots[i] = -1 @@ -82,6 +96,45 @@ func stackalloc(f *Func) { if phiArg[v.ID] { continue } + + // If this is a named value, try to use the name as + // the spill location. + var name GCNode + if v.Op == OpStoreReg { + name = names[v.Args[0].ID] + } else { + name = names[v.ID] + } + if name != nil && v.Type.Equal(name.Typ()) { + for _, id := range interfere[v.ID] { + h := f.getHome(id) + if h != nil && h.(*LocalSlot).N == name { + // A variable can interfere with itself. + // It is rare, but but it can happen. + goto noname + } + } + if v.Op == OpPhi { + for _, a := range v.Args { + for _, id := range interfere[a.ID] { + h := f.getHome(id) + if h != nil && h.(*LocalSlot).N == name { + goto noname + } + } + } + } + loc := &LocalSlot{name} + f.setHome(v, loc) + if v.Op == OpPhi { + for _, a := range v.Args { + f.setHome(a, loc) + } + } + continue + } + + noname: // Set of stack slots we could reuse. locs := locations[v.Type] // Mark all positions in locs used by interfering values. @@ -96,7 +149,7 @@ func stackalloc(f *Func) { } if v.Op == OpPhi { // Stack phi and args must get the same stack slot, so - // anything they interfere with is something v the phi + // anything the args interfere with is something the phi // interferes with. for _, a := range v.Args { for _, xid := range interfere[a.ID] { @@ -209,11 +262,11 @@ func (f *Func) liveSpills() [][][]ID { return live } -func (f *Func) getHome(v *Value) Location { - if int(v.ID) >= len(f.RegAlloc) { +func (f *Func) getHome(vid ID) Location { + if int(vid) >= len(f.RegAlloc) { return nil } - return f.RegAlloc[v.ID] + return f.RegAlloc[vid] } func (f *Func) setHome(v *Value, loc Location) { |