]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: ensure that ssa.Func constant cache is consistent
authorDavid Chase <drchase@google.com>
Fri, 28 Aug 2020 18:32:15 +0000 (14:32 -0400)
committerDavid Chase <drchase@google.com>
Sat, 5 Sep 2020 14:11:21 +0000 (14:11 +0000)
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>
src/cmd/compile/internal/ssa/func.go
src/cmd/compile/internal/ssa/softfloat.go
src/cmd/compile/internal/ssa/value.go

index 6718b778e1d73549764c211d235eb0cbb254120b..32df0c06f3e8a84cc6295df06678108518c564e9 100644 (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
 }
 
index 8db4334fef8536fca94403c5d739bf6660ef0bf8..a8a8f836294b9790c4864f9674aa4dad2b94fe7c 100644 (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 {
index 090745def7bf9fbec1740fc3b8bf6d68a515d77f..6692df7921113e78b8debf1cf4a4ac0970a86e1e 100644 (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)