From 32efa16c3d63dd630e2190a8c0f30c0a941f6fd7 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 1 Apr 2016 14:51:29 -0400 Subject: cmd/compile: added stats printing to stackalloc This is controlled by the "regalloc" stats flag, since regalloc calls stackalloc. The plan is for this to allow comparison of cheaper stack allocation algorithms with what we have now. Change-Id: Ibf64a780344c69babfcbb328fd6d053ea2e02cfc Reviewed-on: https://go-review.googlesource.com/21393 Run-TryBot: David Chase Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/stackalloc.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/cmd/compile/internal/ssa/stackalloc.go') diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 1de22dc96e..e3ef66ab1b 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -22,6 +22,13 @@ type stackAllocState struct { names []LocalSlot slots []int used []bool + + nArgSlot, // Number of Values sourced to arg slot + nNotNeed, // Number of Values not needing a stack slot + nNamedSlot, // Number of Values using a named stack slot + nReuse, // Number of values reusing a stack slot + nAuto, // Number of autos allocated for stack slots. + nSelfInterfere int32 // Number of self-interferences } func newStackAllocState(f *Func) *stackAllocState { @@ -54,6 +61,7 @@ func putStackAllocState(s *stackAllocState) { s.f.Config.stackAllocState = s s.f = nil s.live = nil + s.nArgSlot, s.nNotNeed, s.nNamedSlot, s.nReuse, s.nAuto, s.nSelfInterfere = 0, 0, 0, 0, 0, 0 } type stackValState struct { @@ -75,6 +83,13 @@ func stackalloc(f *Func, spillLive [][]ID) [][]ID { defer putStackAllocState(s) s.stackalloc() + if f.pass.stats > 0 { + f.logStat("stack_alloc_stats", + s.nArgSlot, "arg_slots", s.nNotNeed, "slot_not_needed", + s.nNamedSlot, "named_slots", s.nAuto, "auto_slots", + s.nReuse, "reused_slots", s.nSelfInterfere, "self_interfering") + } + return s.live } @@ -170,9 +185,11 @@ func (s *stackAllocState) stackalloc() { for _, b := range f.Blocks { for _, v := range b.Values { if !s.values[v.ID].needSlot { + s.nNotNeed++ continue } if v.Op == OpArg { + s.nArgSlot++ continue // already picked } @@ -190,12 +207,14 @@ func (s *stackAllocState) stackalloc() { if h != nil && h.(LocalSlot).N == name.N && h.(LocalSlot).Off == name.Off { // A variable can interfere with itself. // It is rare, but but it can happen. + s.nSelfInterfere++ goto noname } } if f.pass.debug > stackDebug { fmt.Printf("stackalloc %s to %s\n", v, name.Name()) } + s.nNamedSlot++ f.setHome(v, name) continue } @@ -217,11 +236,13 @@ func (s *stackAllocState) stackalloc() { var i int for i = 0; i < len(locs); i++ { if !used[i] { + s.nReuse++ break } } // If there is no unused stack slot, allocate a new one. if i == len(locs) { + s.nAuto++ locs = append(locs, LocalSlot{N: f.Config.fe.Auto(v.Type), Type: v.Type, Off: 0}) locations[v.Type] = locs } -- cgit v1.3 From 2563b6f9fe76da6c9f95c7766986f4684b80ae6d Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Sun, 3 Apr 2016 14:44:29 -0700 Subject: cmd/compile/internal/ssa: use Compare instead of Equal They have different semantics. Equal is stricter and is designed for the front-end. Compare is looser and cheaper and is designed for the back-end. To avoid possible regression, remove Equal from ssa.Type. Updates #15043 Change-Id: Ie23ce75ff6b4d01b7982e0a89e6f81b5d099d8d6 Reviewed-on: https://go-review.googlesource.com/21483 Reviewed-by: David Chase Run-TryBot: Josh Bleecher Snyder --- src/cmd/compile/internal/gc/type.go | 13 +++---------- src/cmd/compile/internal/ssa/TODO | 2 -- src/cmd/compile/internal/ssa/cse.go | 2 +- src/cmd/compile/internal/ssa/func.go | 2 +- src/cmd/compile/internal/ssa/stackalloc.go | 4 ++-- src/cmd/compile/internal/ssa/type.go | 11 +---------- 6 files changed, 8 insertions(+), 26 deletions(-) (limited to 'src/cmd/compile/internal/ssa/stackalloc.go') diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go index a44a85bed8..855b070af6 100644 --- a/src/cmd/compile/internal/gc/type.go +++ b/src/cmd/compile/internal/gc/type.go @@ -863,19 +863,12 @@ func (t *Type) SimpleString() string { return Econv(t.Etype) } -func (t *Type) Equal(u ssa.Type) bool { - x, ok := u.(*Type) - return ok && Eqtype(t, x) -} - // Compare compares types for purposes of the SSA back // end, returning an ssa.Cmp (one of CMPlt, CMPeq, CMPgt). // The answers are correct for an optimizer -// or code generator, but not for Go source. -// For example, "type gcDrainFlags int" results in -// two Go-different types that Compare equal. -// The order chosen is also arbitrary, only division into -// equivalence classes (Types that compare CMPeq) matters. +// or code generator, but not necessarily typechecking. +// The order chosen is arbitrary, only consistency and division +// into equivalence classes (Types that compare CMPeq) matters. func (t *Type) Compare(u ssa.Type) ssa.Cmp { x, ok := u.(*Type) // ssa.CompilerType is smaller than gc.Type diff --git a/src/cmd/compile/internal/ssa/TODO b/src/cmd/compile/internal/ssa/TODO index e081856bd3..dad4880994 100644 --- a/src/cmd/compile/internal/ssa/TODO +++ b/src/cmd/compile/internal/ssa/TODO @@ -41,8 +41,6 @@ Future/other ------------ - Start another architecture (arm?) - 64-bit ops on 32-bit machines -- Investigate type equality. During SSA generation, should we use n.Type or (say) TypeBool? - Should we get rid of named types in favor of underlying types during SSA generation? -- Should we introduce a new type equality routine that is less strict than the frontend's? - Infrastructure for enabling/disabling/configuring passes - Modify logging for at least pass=1, to be Warnl compatible diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go index e3f1a1d07d..d501f75e02 100644 --- a/src/cmd/compile/internal/ssa/cse.go +++ b/src/cmd/compile/internal/ssa/cse.go @@ -108,7 +108,7 @@ func cse(f *Func) { break } } - if !equivalent || !v.Type.Equal(w.Type) { + if !equivalent || v.Type.Compare(w.Type) != CMPeq { // w is not equivalent to v. // move it to the end and shrink e. e[j], e[len(e)-1] = e[len(e)-1], e[j] diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index da44f26106..11ff8d3792 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -318,7 +318,7 @@ func (f *Func) constVal(line int32, op Op, t Type, c int64, setAux bool) *Value } vv := f.constants[c] for _, v := range vv { - if v.Op == op && v.Type.Equal(t) { + if v.Op == op && v.Type.Compare(t) == CMPeq { if setAux && v.AuxInt != c { panic(fmt.Sprintf("cached const %s should have AuxInt of %d", v.LongString(), c)) } diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index e3ef66ab1b..44f4096cb2 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -201,7 +201,7 @@ func (s *stackAllocState) stackalloc() { } else { name = names[v.ID] } - if name.N != nil && v.Type.Equal(name.Type) { + if name.N != nil && v.Type.Compare(name.Type) == CMPeq { for _, id := range s.interfere[v.ID] { h := f.getHome(id) if h != nil && h.(LocalSlot).N == name.N && h.(LocalSlot).Off == name.Off { @@ -372,7 +372,7 @@ func (s *stackAllocState) buildInterferenceGraph() { if s.values[v.ID].needSlot { live.remove(v.ID) for _, id := range live.contents() { - if s.values[v.ID].typ.Equal(s.values[id].typ) { + if s.values[v.ID].typ.Compare(s.values[id].typ) == CMPeq { s.interfere[v.ID] = append(s.interfere[v.ID], id) s.interfere[id] = append(s.interfere[id], v.ID) } diff --git a/src/cmd/compile/internal/ssa/type.go b/src/cmd/compile/internal/ssa/type.go index 2a3de282cb..91a4efe78f 100644 --- a/src/cmd/compile/internal/ssa/type.go +++ b/src/cmd/compile/internal/ssa/type.go @@ -40,8 +40,7 @@ type Type interface { String() string SimpleString() string // a coarser generic description of T, e.g. T's underlying type - Equal(Type) bool - Compare(Type) Cmp // compare types, returning one of CMPlt, CMPeq, CMPgt. + Compare(Type) Cmp // compare types, returning one of CMPlt, CMPeq, CMPgt. } // Special compiler-only types. @@ -117,14 +116,6 @@ func (t *CompilerType) Compare(u Type) Cmp { return CMPlt } -func (t *CompilerType) Equal(u Type) bool { - x, ok := u.(*CompilerType) - if !ok { - return false - } - return x == t -} - var ( TypeInvalid = &CompilerType{Name: "invalid"} TypeMem = &CompilerType{Name: "mem", Memory: true} -- cgit v1.3