From: David Chase Date: Fri, 28 Aug 2020 18:32:15 +0000 (-0400) Subject: cmd/compile: ensure that ssa.Func constant cache is consistent X-Git-Tag: go1.16beta1~1125 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=bf833ead6250290dce039ffeee88f20a086b5dbe;p=gostls13.git cmd/compile: ensure that ssa.Func constant cache is consistent It was not necessarily consistent before, we were just lucky. Change-Id: I3a92dc724e0af7b4d810a6a0b7b1d58844eb8f87 Reviewed-on: https://go-review.googlesource.com/c/go/+/251440 Run-TryBot: David Chase TryBot-Result: Gobot Gobot Reviewed-by: Cherry Zhang --- diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 6718b778e1..32df0c06f3 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -257,6 +257,49 @@ func (f *Func) LogStat(key string, args ...interface{}) { f.Warnl(f.Entry.Pos, "\t%s\t%s%s\t%s", n, key, value, f.Name) } +// unCacheLine removes v from f's constant cache "line" for aux, +// resets v.InCache when it is found (and removed), +// and returns whether v was found in that line. +func (f *Func) unCacheLine(v *Value, aux int64) bool { + vv := f.constants[aux] + for i, cv := range vv { + if v == cv { + vv[i] = vv[len(vv)-1] + vv[len(vv)-1] = nil + f.constants[aux] = vv[0 : len(vv)-1] + v.InCache = false + return true + } + } + return false +} + +// unCache removes v from f's constant cache. +func (f *Func) unCache(v *Value) { + if v.InCache { + aux := v.AuxInt + if f.unCacheLine(v, aux) { + return + } + if aux == 0 { + switch v.Op { + case OpConstNil: + aux = constNilMagic + case OpConstSlice: + aux = constSliceMagic + case OpConstString: + aux = constEmptyStringMagic + case OpConstInterface: + aux = constInterfaceMagic + } + if aux != 0 && f.unCacheLine(v, aux) { + return + } + } + f.Fatalf("unCached value %s not found in cache, auxInt=0x%x, adjusted aux=0x%x", v.LongString(), v.AuxInt, aux) + } +} + // freeValue frees a value. It must no longer be referenced or have any args. func (f *Func) freeValue(v *Value) { if v.Block == nil { @@ -270,19 +313,8 @@ func (f *Func) freeValue(v *Value) { } // Clear everything but ID (which we reuse). id := v.ID - - // Values with zero arguments and OpOffPtr values might be cached, so remove them there. - nArgs := opcodeTable[v.Op].argLen - if nArgs == 0 || v.Op == OpOffPtr { - vv := f.constants[v.AuxInt] - for i, cv := range vv { - if v == cv { - vv[i] = vv[len(vv)-1] - vv[len(vv)-1] = nil - f.constants[v.AuxInt] = vv[0 : len(vv)-1] - break - } - } + if v.InCache { + f.unCache(v) } *v = Value{} v.ID = id @@ -548,6 +580,7 @@ func (f *Func) constVal(op Op, t *types.Type, c int64, setAuxInt bool) *Value { v = f.Entry.NewValue0(src.NoXPos, op, t) } f.constants[c] = append(vv, v) + v.InCache = true return v } diff --git a/src/cmd/compile/internal/ssa/softfloat.go b/src/cmd/compile/internal/ssa/softfloat.go index 8db4334fef..a8a8f83629 100644 --- a/src/cmd/compile/internal/ssa/softfloat.go +++ b/src/cmd/compile/internal/ssa/softfloat.go @@ -18,6 +18,7 @@ func softfloat(f *Func) { for _, b := range f.Blocks { for _, v := range b.Values { if v.Type.IsFloat() { + f.unCache(v) switch v.Op { case OpPhi, OpLoad, OpArg: if v.Type.Size() == 4 { diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index 090745def7..6692df7921 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -54,6 +54,9 @@ type Value struct { // nor a slot on Go stack, and the generation of this value is delayed to its use time. OnWasmStack bool + // Is this value in the per-function constant cache? If so, remove from cache before changing it or recycling it. + InCache bool + // Storage for the first three args argstorage [3]*Value } @@ -332,6 +335,9 @@ func (v *Value) resetArgs() { // of cmd/compile by almost 10%, and slows it down. //go:noinline func (v *Value) reset(op Op) { + if v.InCache { + v.Block.Func.unCache(v) + } v.Op = op v.resetArgs() v.AuxInt = 0 @@ -342,6 +348,9 @@ func (v *Value) reset(op Op) { // It modifies v to be (Copy a). //go:noinline func (v *Value) copyOf(a *Value) { + if v.InCache { + v.Block.Func.unCache(v) + } v.Op = OpCopy v.resetArgs() v.AddArg(a)