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 <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
David Chase 2020-08-28 14:32:15 -04:00
parent 721819e7ba
commit bf833ead62
3 changed files with 56 additions and 13 deletions

View File

@ -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
}

View File

@ -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 {

View File

@ -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)