cmd/compile: tweak offset-generator to elide more +0 offsets

this caused a problem in write barrier code when a spurious
zero-offset prevented a write barrier elision.

removed cache after instrumenting it and discovering
zero safe hits (one value must dominate the other, else
unsafe).

Change-Id: I42dfdb4d38ebfe158b13e766a7fabfc514d773f7
Reviewed-on: https://go-review.googlesource.com/c/go/+/297349
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
David Chase 2021-02-27 17:11:36 -05:00
parent 5c5552c5ba
commit d6504b8097

View file

@ -20,12 +20,6 @@ type selKey struct {
typ *types.Type typ *types.Type
} }
type offsetKey struct {
from *Value
offset int64
pt *types.Type
}
type Abi1RO uint8 // An offset within a parameter's slice of register indices, for abi1. type Abi1RO uint8 // An offset within a parameter's slice of register indices, for abi1.
func isBlockMultiValueExit(b *Block) bool { func isBlockMultiValueExit(b *Block) bool {
@ -194,8 +188,7 @@ type expandState struct {
sdom SparseTree sdom SparseTree
commonSelectors map[selKey]*Value // used to de-dupe selectors commonSelectors map[selKey]*Value // used to de-dupe selectors
commonArgs map[selKey]*Value // used to de-dupe OpArg/OpArgIntReg/OpArgFloatReg commonArgs map[selKey]*Value // used to de-dupe OpArg/OpArgIntReg/OpArgFloatReg
offsets map[offsetKey]*Value memForCall map[ID]*Value // For a call, need to know the unique selector that gets the mem.
memForCall map[ID]*Value // For a call, need to know the unique selector that gets the mem.
} }
// intPairTypes returns the pair of 32-bit int types needed to encode a 64-bit integer type on a target // intPairTypes returns the pair of 32-bit int types needed to encode a 64-bit integer type on a target
@ -223,9 +216,16 @@ func (x *expandState) isAlreadyExpandedAggregateType(t *types.Type) bool {
// offsetFrom creates an offset from a pointer, simplifying chained offsets and offsets from SP // offsetFrom creates an offset from a pointer, simplifying chained offsets and offsets from SP
// TODO should also optimize offsets from SB? // TODO should also optimize offsets from SB?
func (x *expandState) offsetFrom(from *Value, offset int64, pt *types.Type) *Value { func (x *expandState) offsetFrom(b *Block, from *Value, offset int64, pt *types.Type) *Value {
if offset == 0 && from.Type == pt { // this is not actually likely ft := from.Type
return from if offset == 0 {
if ft == pt {
return from
}
// This captures common, (apparently) safe cases. The unsafe cases involve ft == uintptr
if (ft.IsPtr() || ft.IsUnsafePtr()) && pt.IsPtr() {
return from
}
} }
// Simplify, canonicalize // Simplify, canonicalize
for from.Op == OpOffPtr { for from.Op == OpOffPtr {
@ -235,14 +235,7 @@ func (x *expandState) offsetFrom(from *Value, offset int64, pt *types.Type) *Val
if from == x.sp { if from == x.sp {
return x.f.ConstOffPtrSP(pt, offset, x.sp) return x.f.ConstOffPtrSP(pt, offset, x.sp)
} }
key := offsetKey{from, offset, pt} return b.NewValue1I(from.Pos.WithNotStmt(), OpOffPtr, pt, offset, from)
v := x.offsets[key]
if v != nil {
return v
}
v = from.Block.NewValue1I(from.Pos.WithNotStmt(), OpOffPtr, pt, offset, from)
x.offsets[key] = v
return v
} }
// splitSlots splits one "field" (specified by sfx, offset, and ty) out of the LocalSlots in ls and returns the new LocalSlots this generates. // splitSlots splits one "field" (specified by sfx, offset, and ty) out of the LocalSlots in ls and returns the new LocalSlots this generates.
@ -426,7 +419,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
leaf.copyOf(w) leaf.copyOf(w)
} }
} else { } else {
off := x.offsetFrom(x.sp, offset+aux.OffsetOfResult(which), pt) off := x.offsetFrom(x.f.Entry, x.sp, offset+aux.OffsetOfResult(which), pt)
if leaf.Block == call.Block { if leaf.Block == call.Block {
leaf.reset(OpLoad) leaf.reset(OpLoad)
leaf.SetArgs2(off, call) leaf.SetArgs2(off, call)
@ -531,7 +524,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
func (x *expandState) rewriteDereference(b *Block, base, a, mem *Value, offset, size int64, typ *types.Type, pos src.XPos) *Value { func (x *expandState) rewriteDereference(b *Block, base, a, mem *Value, offset, size int64, typ *types.Type, pos src.XPos) *Value {
source := a.Args[0] source := a.Args[0]
dst := x.offsetFrom(base, offset, source.Type) dst := x.offsetFrom(b, base, offset, source.Type)
if a.Uses == 1 && a.Block == b { if a.Uses == 1 && a.Block == b {
a.reset(OpMove) a.reset(OpMove)
a.Pos = pos a.Pos = pos
@ -624,7 +617,7 @@ func storeOneArg(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *
// storeOneLoad creates a decomposed (one step) load that is then stored. // storeOneLoad creates a decomposed (one step) load that is then stored.
func storeOneLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value { func storeOneLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
from := x.offsetFrom(source.Args[0], offArg, types.NewPtr(t)) from := x.offsetFrom(b, source.Args[0], offArg, types.NewPtr(t))
w := source.Block.NewValue2(source.Pos, OpLoad, t, from, mem) w := source.Block.NewValue2(source.Pos, OpLoad, t, from, mem)
return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc) return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc)
} }
@ -826,7 +819,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
if storeRc.hasRegs() { if storeRc.hasRegs() {
storeRc.addArg(source) storeRc.addArg(source)
} else { } else {
dst := x.offsetFrom(storeRc.storeDest, offset, types.NewPtr(t)) dst := x.offsetFrom(b, storeRc.storeDest, offset, types.NewPtr(t))
s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem) s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem)
} }
if x.debug { if x.debug {
@ -904,7 +897,6 @@ func expandCalls(f *Func) {
namedSelects: make(map[*Value][]namedVal), namedSelects: make(map[*Value][]namedVal),
sdom: f.Sdom(), sdom: f.Sdom(),
commonArgs: make(map[selKey]*Value), commonArgs: make(map[selKey]*Value),
offsets: make(map[offsetKey]*Value),
memForCall: make(map[ID]*Value), memForCall: make(map[ID]*Value),
} }
@ -1098,7 +1090,7 @@ func expandCalls(f *Func) {
which := v.AuxInt which := v.AuxInt
aux := call.Aux.(*AuxCall) aux := call.Aux.(*AuxCall)
pt := v.Type pt := v.Type
off := x.offsetFrom(x.sp, aux.OffsetOfResult(which), pt) off := x.offsetFrom(x.f.Entry, x.sp, aux.OffsetOfResult(which), pt)
v.copyOf(off) v.copyOf(off)
} }
} }