aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssa/stackalloc.go
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2015-10-22 14:22:38 -0700
committerKeith Randall <khr@golang.org>2015-10-28 17:00:31 +0000
commitc24681ae2e1c96bd67c149cffa8f5ed394e68453 (patch)
tree901661939332bae3a55be8102da790778f1161e8 /src/cmd/compile/internal/ssa/stackalloc.go
parentd43f2e37edf4115e31a0c9218d87182d0aa1c4f0 (diff)
downloadgo-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.go63
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) {