diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index b5478ebb7ce..addecbf168c 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -483,6 +483,11 @@ func Main() { } } + // Prepare for SSA compilation. + // This must be before peekitabs, because peekitabs + // can trigger function compilation. + initssaconfig() + // Just before compilation, compile itabs found on // the right side of OCONVIFACE so that methods // can be de-virtualized during compilation. diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index d5978bb2391..4b29bb83ae4 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -411,7 +411,6 @@ func compile(fn *Node) { gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps) genssa(ssafn, ptxt, gcargs, gclocals) - ssafn.Free() obj.Flushplist(Ctxt, plist) // convert from Prog list to machine code ptxt = nil // nil to prevent misuse; Prog may have been freed by Flushplist diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 4aca79307ad..bd04ff536e6 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -20,16 +20,14 @@ import ( var ssaConfig *ssa.Config var ssaExp ssaExport +var ssaCache *ssa.Cache -func initssa() *ssa.Config { - if ssaConfig == nil { - ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0) - if Thearch.LinkArch.Name == "386" { - ssaConfig.Set387(Thearch.Use387) - } +func initssaconfig() { + ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0) + if Thearch.LinkArch.Name == "386" { + ssaConfig.Set387(Thearch.Use387) } - ssaConfig.HTML = nil - return ssaConfig + ssaCache = new(ssa.Cache) } // buildssa builds an SSA function. @@ -51,12 +49,15 @@ func buildssa(fn *Node) *ssa.Func { if fn.Func.Pragma&CgoUnsafeArgs != 0 { s.cgoUnsafeArgs = true } - // TODO(khr): build config just once at the start of the compiler binary ssaExp.log = printssa - s.config = initssa() - s.f = s.config.NewFunc() + s.f = ssa.NewFunc() + s.config = ssaConfig + s.f.Config = ssaConfig + s.f.Cache = ssaCache + s.f.Cache.Reset() + s.f.DebugTest = s.f.DebugHashMatch("GOSSAHASH", name) s.f.Name = name if fn.Func.Pragma&Nosplit != 0 { s.f.NoSplit = true @@ -71,12 +72,9 @@ func buildssa(fn *Node) *ssa.Func { }() s.exitCode = fn.Func.Exit s.panics = map[funcLine]*ssa.Block{} - s.config.DebugTest = s.config.DebugHashMatch("GOSSAHASH", name) if name == os.Getenv("GOSSAFUNC") { - // TODO: tempfile? it is handy to have the location - // of this file be stable, so you can just reload in the browser. - s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name) + s.f.HTMLWriter = ssa.NewHTMLWriter("ssa.html", ssaConfig, name) // TODO: generate and print a mapping from nodes to values and blocks } @@ -140,7 +138,6 @@ func buildssa(fn *Node) *ssa.Func { } if nerrors > 0 { - s.f.Free() return nil } @@ -152,7 +149,6 @@ func buildssa(fn *Node) *ssa.Func { // Main call to ssa package to compile function ssa.Compile(s.f) if nerrors > 0 { - s.f.Free() return nil } @@ -4287,7 +4283,7 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) { } f.Logf("%s\t%s\n", s, p) } - if f.Config.HTML != nil { + if f.HTMLWriter != nil { // LineHist is defunct now - this code won't do // anything. // TODO: fix this (ideally without a global variable) @@ -4311,7 +4307,7 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) { } buf.WriteString("") buf.WriteString("") - f.Config.HTML.WriteColumn("genssa", buf.String()) + f.HTMLWriter.WriteColumn("genssa", buf.String()) // ptxt.Ctxt.LineHist.PrintFilenameOnly = saved } } @@ -4328,8 +4324,8 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) { // Remove leftover instrumentation from the instruction stream. removevardef(ptxt) - f.Config.HTML.Close() - f.Config.HTML = nil + f.HTMLWriter.Close() + f.HTMLWriter = nil } type FloatingEQNEJump struct { diff --git a/src/cmd/compile/internal/ssa/cache.go b/src/cmd/compile/internal/ssa/cache.go index 64f9659520d..f1018da497f 100644 --- a/src/cmd/compile/internal/ssa/cache.go +++ b/src/cmd/compile/internal/ssa/cache.go @@ -4,7 +4,38 @@ package ssa +import "sort" + // A Cache holds reusable compiler state. // It is intended to be re-used for multiple Func compilations. type Cache struct { + // Storage for low-numbered values and blocks. + values [2000]Value + blocks [200]Block + locs [2000]Location + + // Reusable stackAllocState. + // See stackalloc.go's {new,put}StackAllocState. + stackAllocState *stackAllocState + + domblockstore []ID // scratch space for computing dominators + scrSparse []*sparseSet // scratch sparse sets to be re-used. +} + +func (c *Cache) Reset() { + nv := sort.Search(len(c.values), func(i int) bool { return c.values[i].ID == 0 }) + xv := c.values[:nv] + for i := range xv { + xv[i] = Value{} + } + nb := sort.Search(len(c.blocks), func(i int) bool { return c.blocks[i].ID == 0 }) + xb := c.blocks[:nb] + for i := range xb { + xb[i] = Block{} + } + nl := sort.Search(len(c.locs), func(i int) bool { return c.locs[i] == nil }) + xl := c.locs[:nl] + for i := range xl { + xl[i] = nil + } } diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index c03436cdf06..4f62250dc5d 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -43,7 +43,7 @@ func Compile(f *Func) { // Run all the passes printFunc(f) - f.Config.HTML.WriteFunc("start", f) + f.HTMLWriter.WriteFunc("start", f) if BuildDump != "" && BuildDump == f.Name { f.dumpFile("build") } @@ -71,7 +71,7 @@ func Compile(f *Func) { tEnd := time.Now() // Need something less crude than "Log the whole intermediate result". - if f.Log() || f.Config.HTML != nil { + if f.Log() || f.HTMLWriter != nil { time := tEnd.Sub(tStart).Nanoseconds() var stats string if logMemStats { @@ -86,7 +86,7 @@ func Compile(f *Func) { f.Logf(" pass %s end %s\n", p.name, stats) printFunc(f) - f.Config.HTML.WriteFunc(fmt.Sprintf("after %s %s", phaseName, stats), f) + f.HTMLWriter.WriteFunc(fmt.Sprintf("after %s %s", phaseName, stats), f) } if p.time || p.mem { // Surround timing information w/ enough context to allow comparisons. diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index ce7adaf3d58..589b7c9b1ef 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -32,7 +32,6 @@ type Config struct { LinkReg int8 // register number of link register if it is a general purpose register, -1 if not used hasGReg bool // has hardware g register fe Frontend // callbacks into compiler frontend - HTML *HTMLWriter // html writer, for debugging ctxt *obj.Link // Generic arch information optimize bool // Do optimization noDuffDevice bool // Don't use Duff's device @@ -41,27 +40,7 @@ type Config struct { OldArch bool // True for older versions of architecture, e.g. true for PPC64BE, false for PPC64LE NeedsFpScratch bool // No direct move between GP and FP register sets BigEndian bool // - DebugTest bool // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score - curFunc *Func - - // TODO: more stuff. Compiler flags of interest, ... - - // Given an environment variable used for debug hash match, - // what file (if any) receives the yes/no logging? - logfiles map[string]*os.File - - // Storage for low-numbered values and blocks. - values [2000]Value - blocks [200]Block - locs [2000]Location - - // Reusable stackAllocState. - // See stackalloc.go's {new,put}StackAllocState. - stackAllocState *stackAllocState - - domblockstore []ID // scratch space for computing dominators - scrSparse []*sparseSet // scratch sparse sets to be re-used. } type TypeSource interface { @@ -304,16 +283,6 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config opcodeTable[OpARMCALLudiv].reg.clobbers |= 1 << 12 // R12 } - // Assign IDs to preallocated values/blocks. - for i := range c.values { - c.values[i].ID = ID(i) - } - for i := range c.blocks { - c.blocks[i].ID = ID(i) - } - - c.logfiles = make(map[string]*os.File) - // cutoff is compared with product of numblocks and numvalues, // if product is smaller than cutoff, use old non-sparse method. // cutoff == 0 implies all sparse. @@ -342,18 +311,6 @@ func (c *Config) Frontend() Frontend { return c.fe } func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff } func (c *Config) Ctxt() *obj.Link { return c.ctxt } -// NewFunc returns a new, empty function object. -// Caller must call f.Free() before calling NewFunc again. -func (c *Config) NewFunc() *Func { - // TODO(khr): should this function take name, type, etc. as arguments? - if c.curFunc != nil { - c.Fatalf(src.NoXPos, "NewFunc called without previous Free") - } - f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}} - c.curFunc = f - return f -} - func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) } func (c *Config) Log() bool { return c.fe.Log() } func (c *Config) Fatalf(pos src.XPos, msg string, args ...interface{}) { c.fe.Fatalf(pos, msg, args...) } @@ -362,8 +319,11 @@ func (c *Config) Warnl(pos src.XPos, msg string, args ...interface{}) { c.fe.Wa func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() } func (c *Config) Debug_wb() bool { return c.fe.Debug_wb() } -func (c *Config) logDebugHashMatch(evname, name string) { - file := c.logfiles[evname] +func (f *Func) logDebugHashMatch(evname, name string) { + if f.logfiles == nil { + f.logfiles = make(map[string]*os.File) + } + file := f.logfiles[evname] if file == nil { file = os.Stdout tmpfile := os.Getenv("GSHS_LOGFILE") @@ -371,10 +331,10 @@ func (c *Config) logDebugHashMatch(evname, name string) { var ok error file, ok = os.Create(tmpfile) if ok != nil { - c.Fatalf(src.NoXPos, "Could not open hash-testing logfile %s", tmpfile) + f.Fatalf("could not open hash-testing logfile %s", tmpfile) } } - c.logfiles[evname] = file + f.logfiles[evname] = file } s := fmt.Sprintf("%s triggered %s\n", evname, name) file.WriteString(s) @@ -395,14 +355,13 @@ func (c *Config) logDebugHashMatch(evname, name string) { // GSHS_LOGFILE // or standard out if that is empty or there is an error // opening the file. - -func (c *Config) DebugHashMatch(evname, name string) bool { +func (f *Func) DebugHashMatch(evname, name string) bool { evhash := os.Getenv(evname) if evhash == "" { return true // default behavior with no EV is "on" } if evhash == "y" || evhash == "Y" { - c.logDebugHashMatch(evname, name) + f.logDebugHashMatch(evname, name) return true } if evhash == "n" || evhash == "N" { @@ -417,7 +376,7 @@ func (c *Config) DebugHashMatch(evname, name string) bool { } if strings.HasSuffix(hstr, evhash) { - c.logDebugHashMatch(evname, name) + f.logDebugHashMatch(evname, name) return true } @@ -430,13 +389,13 @@ func (c *Config) DebugHashMatch(evname, name string) bool { break } if strings.HasSuffix(hstr, evv) { - c.logDebugHashMatch(ev, name) + f.logDebugHashMatch(ev, name) return true } } return false } -func (c *Config) DebugNameMatch(evname, name string) bool { +func DebugNameMatch(evname, name string) bool { return os.Getenv(evname) == name } diff --git a/src/cmd/compile/internal/ssa/copyelim_test.go b/src/cmd/compile/internal/ssa/copyelim_test.go index 96f5846850a..34c548a48b1 100644 --- a/src/cmd/compile/internal/ssa/copyelim_test.go +++ b/src/cmd/compile/internal/ssa/copyelim_test.go @@ -36,6 +36,5 @@ func benchmarkCopyElim(b *testing.B, n int) { for i := 0; i < b.N; i++ { fun := Fun(c, "entry", Bloc("entry", values...)) Copyelim(fun.f) - fun.f.Free() } } diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index b1d8d0fff02..c8ee3662fdc 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -154,7 +154,6 @@ func BenchmarkDeadCode(b *testing.B) { for i := 0; i < b.N; i++ { fun := Fun(c, "entry", blocks...) Deadcode(fun.f) - fun.f.Free() } }) } diff --git a/src/cmd/compile/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go index 3dae5fbf076..89347be54f9 100644 --- a/src/cmd/compile/internal/ssa/dom.go +++ b/src/cmd/compile/internal/ssa/dom.go @@ -70,9 +70,9 @@ const nscratchslices = 7 // in make.bash. const minscratchblocks = 512 -func (cfg *Config) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g []ID) { +func (cache *Cache) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g []ID) { tot := maxBlockID * nscratchslices - scratch := cfg.domblockstore + scratch := cache.domblockstore if len(scratch) < tot { // req = min(1.5*tot, nscratchslices*minscratchblocks) // 50% padding allows for graph growth in later phases. @@ -81,7 +81,7 @@ func (cfg *Config) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g []ID req = nscratchslices * minscratchblocks } scratch = make([]ID, req) - cfg.domblockstore = scratch + cache.domblockstore = scratch } else { // Clear as much of scratch as we will (re)use scratch = scratch[0:tot] @@ -117,7 +117,7 @@ func (f *Func) dominatorsLTOrig(entry *Block, predFn linkedBlocks, succFn linked // Adapted directly from the original TOPLAS article's "simple" algorithm maxBlockID := entry.Func.NumBlocks() - semi, vertex, label, parent, ancestor, bucketHead, bucketLink := f.Config.scratchBlocksForDom(maxBlockID) + semi, vertex, label, parent, ancestor, bucketHead, bucketLink := f.Cache.scratchBlocksForDom(maxBlockID) // This version uses integers for most of the computation, // to make the work arrays smaller and pointer-free. diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index a26c92ef87e..86824670536 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -8,6 +8,7 @@ import ( "cmd/internal/src" "fmt" "math" + "os" "strings" ) @@ -16,6 +17,7 @@ import ( // Funcs are single-use; a new Func must be created for every compiled function. type Func struct { Config *Config // architecture information + Cache *Cache // re-usable cache pass *pass // current pass information (name, options, etc.) Name string // e.g. bytes·Compare Type Type // type signature of the function. @@ -24,6 +26,12 @@ type Func struct { bid idAlloc // block ID allocator vid idAlloc // value ID allocator + // Given an environment variable used for debug hash match, + // what file (if any) receives the yes/no logging? + logfiles map[string]*os.File + HTMLWriter *HTMLWriter // html writer, for debugging + DebugTest bool // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases + scheduled bool // Values in Blocks are in final order NoSplit bool // true if function is marked as nosplit. Used by schedule check pass. @@ -52,6 +60,12 @@ type Func struct { constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type } +// NewFunc returns a new, empty function object. +// Caller must set f.Config and f.Cache before using f. +func NewFunc() *Func { + return &Func{NamedValues: make(map[LocalSlot][]*Value)} +} + // NumBlocks returns an integer larger than the id of any Block in the Func. func (f *Func) NumBlocks() int { return f.bid.num() @@ -64,9 +78,9 @@ func (f *Func) NumValues() int { // newSparseSet returns a sparse set that can store at least up to n integers. func (f *Func) newSparseSet(n int) *sparseSet { - for i, scr := range f.Config.scrSparse { + for i, scr := range f.Cache.scrSparse { if scr != nil && scr.cap() >= n { - f.Config.scrSparse[i] = nil + f.Cache.scrSparse[i] = nil scr.clear() return scr } @@ -76,13 +90,13 @@ func (f *Func) newSparseSet(n int) *sparseSet { // retSparseSet returns a sparse set to the config's cache of sparse sets to be reused by f.newSparseSet. func (f *Func) retSparseSet(ss *sparseSet) { - for i, scr := range f.Config.scrSparse { + for i, scr := range f.Cache.scrSparse { if scr == nil { - f.Config.scrSparse[i] = ss + f.Cache.scrSparse[i] = ss return } } - f.Config.scrSparse = append(f.Config.scrSparse, ss) + f.Cache.scrSparse = append(f.Cache.scrSparse, ss) } // newValue allocates a new Value with the given fields and places it at the end of b.Values. @@ -94,8 +108,9 @@ func (f *Func) newValue(op Op, t Type, b *Block, pos src.XPos) *Value { v.argstorage[0] = nil } else { ID := f.vid.get() - if int(ID) < len(f.Config.values) { - v = &f.Config.values[ID] + if int(ID) < len(f.Cache.values) { + v = &f.Cache.values[ID] + v.ID = ID } else { v = &Value{ID: ID} } @@ -120,8 +135,9 @@ func (f *Func) newValueNoBlock(op Op, t Type, pos src.XPos) *Value { v.argstorage[0] = nil } else { ID := f.vid.get() - if int(ID) < len(f.Config.values) { - v = &f.Config.values[ID] + if int(ID) < len(f.Cache.values) { + v = &f.Cache.values[ID] + v.ID = ID } else { v = &Value{ID: ID} } @@ -190,8 +206,9 @@ func (f *Func) NewBlock(kind BlockKind) *Block { b.succstorage[0].b = nil } else { ID := f.bid.get() - if int(ID) < len(f.Config.blocks) { - b = &f.Config.blocks[ID] + if int(ID) < len(f.Cache.blocks) { + b = &f.Cache.blocks[ID] + b.ID = ID } else { b = &Block{ID: ID} } @@ -468,48 +485,6 @@ func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args func (f *Func) Log() bool { return f.Config.Log() } func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(f.Entry.Pos, msg, args...) } -func (f *Func) Free() { - // Clear cached CFG info. - f.invalidateCFG() - - // Clear values. - n := f.vid.num() - if n > len(f.Config.values) { - n = len(f.Config.values) - } - for i := 1; i < n; i++ { - f.Config.values[i] = Value{} - f.Config.values[i].ID = ID(i) - } - - // Clear blocks. - n = f.bid.num() - if n > len(f.Config.blocks) { - n = len(f.Config.blocks) - } - for i := 1; i < n; i++ { - f.Config.blocks[i] = Block{} - f.Config.blocks[i].ID = ID(i) - } - - // Clear locs. - n = len(f.RegAlloc) - if n > len(f.Config.locs) { - n = len(f.Config.locs) - } - head := f.Config.locs[:n] - for i := range head { - head[i] = nil - } - - // Unregister from config. - if f.Config.curFunc != f { - f.Fatalf("free of function which isn't the last one allocated") - } - f.Config.curFunc = nil - *f = Func{} // just in case -} - // postorder returns the reachable blocks in f in a postorder traversal. func (f *Func) postorder() []*Block { if f.cachedPostorder == nil { diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index 580f67717a8..b14da75b1aa 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -144,7 +144,12 @@ var emptyPass pass = pass{ // supplied to one of the Bloc functions. Each of the bloc names and // valu names should be unique across the Fun. func Fun(c *Config, entry string, blocs ...bloc) fun { - f := c.NewFunc() + f := NewFunc() + f.Config = c + // TODO: Either mark some SSA tests as t.Parallel, + // or set up a shared Cache and Reset it between tests. + // But not both. + f.Cache = new(Cache) f.pass = &emptyPass blocks := make(map[string]*Block) diff --git a/src/cmd/compile/internal/ssa/fuse_test.go b/src/cmd/compile/internal/ssa/fuse_test.go index b316a482618..cf21ac468f3 100644 --- a/src/cmd/compile/internal/ssa/fuse_test.go +++ b/src/cmd/compile/internal/ssa/fuse_test.go @@ -162,7 +162,6 @@ func BenchmarkFuse(b *testing.B) { for i := 0; i < b.N; i++ { fun := Fun(c, "entry", blocks...) fuse(fun.f) - fun.f.Free() } }) } diff --git a/src/cmd/compile/internal/ssa/loop_test.go b/src/cmd/compile/internal/ssa/loop_test.go index 901ca5cf04e..ddd14c2c016 100644 --- a/src/cmd/compile/internal/ssa/loop_test.go +++ b/src/cmd/compile/internal/ssa/loop_test.go @@ -82,6 +82,4 @@ func TestLoopConditionS390X(t *testing.T) { OpS390XCMP: 1, OpS390XCMPWconst: 0, }) - - fun.f.Free() } diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 95f2f7c91a0..cf305b027e4 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -495,7 +495,7 @@ func isLeaf(f *Func) bool { func (s *regAllocState) init(f *Func) { s.f = f - s.f.RegAlloc = s.f.Config.locs[:0] + s.f.RegAlloc = s.f.Cache.locs[:0] s.registers = f.Config.registers if nr := len(s.registers); nr == 0 || nr > int(noRegister) || nr > int(unsafe.Sizeof(regMask(0))*8) { s.f.Fatalf("bad number of registers: %d", nr) diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index 8a3a429e18e..de4d25a93fc 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -12,22 +12,21 @@ func TestShiftConstAMD64(t *testing.T) { c := testConfig(t) fun := makeConstShiftFunc(c, 18, OpLsh64x64, TypeUInt64) checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0}) - fun.f.Free() + fun = makeConstShiftFunc(c, 66, OpLsh64x64, TypeUInt64) checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 0, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0}) - fun.f.Free() + fun = makeConstShiftFunc(c, 18, OpRsh64Ux64, TypeUInt64) checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHRQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0}) - fun.f.Free() + fun = makeConstShiftFunc(c, 66, OpRsh64Ux64, TypeUInt64) checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHRQconst: 0, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0}) - fun.f.Free() + fun = makeConstShiftFunc(c, 18, OpRsh64x64, TypeInt64) checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SARQconst: 1, OpAMD64CMPQconst: 0}) - fun.f.Free() + fun = makeConstShiftFunc(c, 66, OpRsh64x64, TypeInt64) checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SARQconst: 1, OpAMD64CMPQconst: 0}) - fun.f.Free() } func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun { @@ -80,7 +79,6 @@ func TestShiftToExtensionAMD64(t *testing.T) { for _, tc := range tests { fun := makeShiftExtensionFunc(c, tc.amount, tc.left, tc.right, tc.typ) checkOpcodeCounts(t, fun.f, ops) - fun.f.Free() } } diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index cdc40e5a35f..40edfc55c6e 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -35,7 +35,7 @@ type stackAllocState struct { } func newStackAllocState(f *Func) *stackAllocState { - s := f.Config.stackAllocState + s := f.Cache.stackAllocState if s == nil { return new(stackAllocState) } @@ -61,7 +61,7 @@ func putStackAllocState(s *stackAllocState) { for i := range s.used { s.used[i] = false } - s.f.Config.stackAllocState = s + s.f.Cache.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