mirror of https://github.com/golang/go.git
parent
5dcc04aeac
commit
e15c9f7a33
|
|
@ -21,14 +21,18 @@ func dse(f *Func) {
|
|||
defer f.retSparseSet(storeUse)
|
||||
shadowed := f.newSparseMap(f.NumValues())
|
||||
defer f.retSparseMap(shadowed)
|
||||
localAddrs := f.newSparseSet(f.NumValues())
|
||||
defer f.retSparseSet(localAddrs)
|
||||
for _, b := range f.Blocks {
|
||||
// Find all the stores in this block. Categorize their uses:
|
||||
// loadUse contains stores which are used by a subsequent load.
|
||||
// storeUse contains stores which are used by a subsequent store.
|
||||
// localAddrs contains indexes into b.Values for each unique LocalAddr.
|
||||
loadUse.clear()
|
||||
storeUse.clear()
|
||||
localAddrs.clear()
|
||||
stores = stores[:0]
|
||||
for _, v := range b.Values {
|
||||
for i, v := range b.Values {
|
||||
if v.Op == OpPhi {
|
||||
// Ignore phis - they will always be first and can't be eliminated
|
||||
continue
|
||||
|
|
@ -46,6 +50,12 @@ func dse(f *Func) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if v.Op == OpLocalAddr {
|
||||
if findSameLocalAddr(b, v, localAddrs) >= 0 {
|
||||
continue
|
||||
}
|
||||
localAddrs.add(ID(i))
|
||||
}
|
||||
for _, a := range v.Args {
|
||||
if a.Block == b && a.Type.IsMemory() {
|
||||
loadUse.add(a.ID)
|
||||
|
|
@ -100,6 +110,10 @@ func dse(f *Func) {
|
|||
} else { // OpZero
|
||||
sz = v.AuxInt
|
||||
}
|
||||
idx := findSameLocalAddr(b, ptr, localAddrs)
|
||||
if idx != -1 {
|
||||
ptr = b.Values[idx]
|
||||
}
|
||||
sr := shadowRange(shadowed.get(ptr.ID))
|
||||
if sr.contains(off, off+sz) {
|
||||
// Modify the store/zero into a copy of the memory state,
|
||||
|
|
@ -136,6 +150,16 @@ func dse(f *Func) {
|
|||
}
|
||||
}
|
||||
|
||||
func findSameLocalAddr(b *Block, vv *Value, localAddrs *sparseSet) int {
|
||||
for _, idx := range localAddrs.contents() {
|
||||
la := b.Values[idx]
|
||||
if isSamePtr(la, vv) {
|
||||
return int(idx)
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// A shadowRange encodes a set of byte offsets [lo():hi()] from
|
||||
// a given pointer that will be written to later in the block.
|
||||
// A zero shadowRange encodes an empty shadowed range (and so
|
||||
|
|
@ -146,6 +170,7 @@ type shadowRange int32
|
|||
func (sr shadowRange) lo() int64 {
|
||||
return int64(sr & 0xffff)
|
||||
}
|
||||
|
||||
func (sr shadowRange) hi() int64 {
|
||||
return int64((sr >> 16) & 0xffff)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package ssa
|
|||
|
||||
import (
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/src"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -44,6 +45,7 @@ func TestDeadStore(t *testing.T) {
|
|||
t.Errorf("dead store (zero) not removed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeadStorePhi(t *testing.T) {
|
||||
// make sure we don't get into an infinite loop with phi values.
|
||||
c := testConfig(t)
|
||||
|
|
@ -127,3 +129,46 @@ func TestDeadStoreUnsafe(t *testing.T) {
|
|||
t.Errorf("store %s incorrectly removed", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeadStoreSmallStructInit(t *testing.T) {
|
||||
c := testConfig(t)
|
||||
ptrType := c.config.Types.BytePtr
|
||||
typ := types.NewStruct([]*types.Field{
|
||||
types.NewField(src.NoXPos, &types.Sym{Name: "A"}, c.config.Types.Int),
|
||||
types.NewField(src.NoXPos, &types.Sym{Name: "B"}, c.config.Types.Int),
|
||||
})
|
||||
name := c.Temp(typ)
|
||||
fun := c.Fun("entry",
|
||||
Bloc("entry",
|
||||
Valu("start", OpInitMem, types.TypeMem, 0, nil),
|
||||
Valu("sp", OpSP, c.config.Types.Uintptr, 0, nil),
|
||||
Valu("zero", OpConst64, c.config.Types.Int, 0, nil),
|
||||
Valu("v6", OpLocalAddr, ptrType, 0, name, "sp", "start"),
|
||||
Valu("v3", OpOffPtr, ptrType, 8, nil, "v6"),
|
||||
Valu("v22", OpOffPtr, ptrType, 0, nil, "v6"),
|
||||
Valu("zerostore1", OpStore, types.TypeMem, 0, c.config.Types.Int, "v22", "zero", "start"),
|
||||
Valu("zerostore2", OpStore, types.TypeMem, 0, c.config.Types.Int, "v3", "zero", "zerostore1"),
|
||||
Valu("v8", OpLocalAddr, ptrType, 0, name, "sp", "zerostore2"),
|
||||
Valu("v23", OpOffPtr, ptrType, 8, nil, "v8"),
|
||||
Valu("v25", OpOffPtr, ptrType, 0, nil, "v8"),
|
||||
Valu("zerostore3", OpStore, types.TypeMem, 0, c.config.Types.Int, "v25", "zero", "zerostore2"),
|
||||
Valu("zerostore4", OpStore, types.TypeMem, 0, c.config.Types.Int, "v23", "zero", "zerostore3"),
|
||||
Goto("exit")),
|
||||
Bloc("exit",
|
||||
Exit("zerostore4")))
|
||||
|
||||
fun.f.Name = "smallstructinit"
|
||||
CheckFunc(fun.f)
|
||||
cse(fun.f)
|
||||
dse(fun.f)
|
||||
CheckFunc(fun.f)
|
||||
|
||||
v1 := fun.values["zerostore1"]
|
||||
if v1.Op != OpCopy {
|
||||
t.Errorf("dead store not removed")
|
||||
}
|
||||
v2 := fun.values["zerostore2"]
|
||||
if v2.Op != OpCopy {
|
||||
t.Errorf("dead store not removed")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue