Skip to content

Commit a7277e5

Browse files
committed
cmd/compile: compare size in dead store elimination
Only remove stores that is shadowed by another store with same or larger size. Normally we don't need this check because we did check the types, but unsafe pointer casting can get around it. Fixes #16769. Change-Id: I3f7c6c57807b590a2f735007dec6c65a4fa01a34 Reviewed-on: https://go-review.googlesource.com/27320 Run-TryBot: Cherry Zhang <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 5b9ff11 commit a7277e5

File tree

2 files changed

+46
-9
lines changed

2 files changed

+46
-9
lines changed

src/cmd/compile/internal/ssa/deadstore.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ func dse(f *Func) {
1414
defer f.retSparseSet(loadUse)
1515
storeUse := f.newSparseSet(f.NumValues())
1616
defer f.retSparseSet(storeUse)
17-
shadowed := f.newSparseSet(f.NumValues())
18-
defer f.retSparseSet(shadowed)
17+
shadowed := newSparseMap(f.NumValues()) // TODO: cache
1918
for _, b := range f.Blocks {
2019
// Find all the stores in this block. Categorize their uses:
2120
// loadUse contains stores which are used by a subsequent load.
@@ -81,25 +80,34 @@ func dse(f *Func) {
8180
shadowed.clear()
8281
}
8382
if v.Op == OpStore || v.Op == OpZero {
84-
if shadowed.contains(v.Args[0].ID) {
83+
var sz int64
84+
if v.Op == OpStore {
85+
sz = v.AuxInt
86+
} else { // OpZero
87+
sz = SizeAndAlign(v.AuxInt).Size()
88+
}
89+
if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz {
8590
// Modify store into a copy
8691
if v.Op == OpStore {
8792
// store addr value mem
8893
v.SetArgs1(v.Args[2])
8994
} else {
9095
// zero addr mem
91-
sz := v.Args[0].Type.ElemType().Size()
92-
if SizeAndAlign(v.AuxInt).Size() != sz {
96+
typesz := v.Args[0].Type.ElemType().Size()
97+
if sz != typesz {
9398
f.Fatalf("mismatched zero/store sizes: %d and %d [%s]",
94-
v.AuxInt, sz, v.LongString())
99+
sz, typesz, v.LongString())
95100
}
96101
v.SetArgs1(v.Args[1])
97102
}
98103
v.Aux = nil
99104
v.AuxInt = 0
100105
v.Op = OpCopy
101106
} else {
102-
shadowed.add(v.Args[0].ID)
107+
if sz > 0x7fffffff { // work around sparseMap's int32 value type
108+
sz = 0x7fffffff
109+
}
110+
shadowed.set(v.Args[0].ID, int32(sz))
103111
}
104112
}
105113
// walk to previous store

src/cmd/compile/internal/ssa/deadstore_test.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import "testing"
88

99
func TestDeadStore(t *testing.T) {
1010
c := testConfig(t)
11-
elemType := &TypeImpl{Size_: 8, Name: "testtype"}
11+
elemType := &TypeImpl{Size_: 1, Name: "testtype"}
1212
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr", Elem_: elemType} // dummy for testing
1313
fun := Fun(c, "entry",
1414
Bloc("entry",
@@ -18,7 +18,7 @@ func TestDeadStore(t *testing.T) {
1818
Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
1919
Valu("addr2", OpAddr, ptrType, 0, nil, "sb"),
2020
Valu("addr3", OpAddr, ptrType, 0, nil, "sb"),
21-
Valu("zero1", OpZero, TypeMem, 8, nil, "addr3", "start"),
21+
Valu("zero1", OpZero, TypeMem, 1, nil, "addr3", "start"),
2222
Valu("store1", OpStore, TypeMem, 1, nil, "addr1", "v", "zero1"),
2323
Valu("store2", OpStore, TypeMem, 1, nil, "addr2", "v", "store1"),
2424
Valu("store3", OpStore, TypeMem, 1, nil, "addr1", "v", "store2"),
@@ -95,3 +95,32 @@ func TestDeadStoreTypes(t *testing.T) {
9595
t.Errorf("store %s incorrectly removed", v)
9696
}
9797
}
98+
99+
func TestDeadStoreUnsafe(t *testing.T) {
100+
// Make sure a narrow store can't shadow a wider one. The test above
101+
// covers the case of two different types, but unsafe pointer casting
102+
// can get to a point where the size is changed but type unchanged.
103+
c := testConfig(t)
104+
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
105+
fun := Fun(c, "entry",
106+
Bloc("entry",
107+
Valu("start", OpInitMem, TypeMem, 0, nil),
108+
Valu("sb", OpSB, TypeInvalid, 0, nil),
109+
Valu("v", OpConstBool, TypeBool, 1, nil),
110+
Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
111+
Valu("store1", OpStore, TypeMem, 8, nil, "addr1", "v", "start"), // store 8 bytes
112+
Valu("store2", OpStore, TypeMem, 1, nil, "addr1", "v", "store1"), // store 1 byte
113+
Goto("exit")),
114+
Bloc("exit",
115+
Exit("store2")))
116+
117+
CheckFunc(fun.f)
118+
cse(fun.f)
119+
dse(fun.f)
120+
CheckFunc(fun.f)
121+
122+
v := fun.values["store1"]
123+
if v.Op == OpCopy {
124+
t.Errorf("store %s incorrectly removed", v)
125+
}
126+
}

0 commit comments

Comments
 (0)