• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ssa
6
7import (
8	"cmd/compile/internal/types"
9	"cmd/internal/src"
10	"testing"
11)
12
13func TestDeadStore(t *testing.T) {
14	c := testConfig(t)
15	ptrType := c.config.Types.BytePtr
16	t.Logf("PTRTYPE %v", ptrType)
17	fun := c.Fun("entry",
18		Bloc("entry",
19			Valu("start", OpInitMem, types.TypeMem, 0, nil),
20			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
21			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
22			Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
23			Valu("addr2", OpAddr, ptrType, 0, nil, "sb"),
24			Valu("addr3", OpAddr, ptrType, 0, nil, "sb"),
25			Valu("zero1", OpZero, types.TypeMem, 1, c.config.Types.Bool, "addr3", "start"),
26			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "zero1"),
27			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr2", "v", "store1"),
28			Valu("store3", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "store2"),
29			Valu("store4", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr3", "v", "store3"),
30			Goto("exit")),
31		Bloc("exit",
32			Exit("store3")))
33
34	CheckFunc(fun.f)
35	dse(fun.f)
36	CheckFunc(fun.f)
37
38	v1 := fun.values["store1"]
39	if v1.Op != OpCopy {
40		t.Errorf("dead store not removed")
41	}
42
43	v2 := fun.values["zero1"]
44	if v2.Op != OpCopy {
45		t.Errorf("dead store (zero) not removed")
46	}
47}
48
49func TestDeadStorePhi(t *testing.T) {
50	// make sure we don't get into an infinite loop with phi values.
51	c := testConfig(t)
52	ptrType := c.config.Types.BytePtr
53	fun := c.Fun("entry",
54		Bloc("entry",
55			Valu("start", OpInitMem, types.TypeMem, 0, nil),
56			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
57			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
58			Valu("addr", OpAddr, ptrType, 0, nil, "sb"),
59			Goto("loop")),
60		Bloc("loop",
61			Valu("phi", OpPhi, types.TypeMem, 0, nil, "start", "store"),
62			Valu("store", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr", "v", "phi"),
63			If("v", "loop", "exit")),
64		Bloc("exit",
65			Exit("store")))
66
67	CheckFunc(fun.f)
68	dse(fun.f)
69	CheckFunc(fun.f)
70}
71
72func TestDeadStoreTypes(t *testing.T) {
73	// Make sure a narrow store can't shadow a wider one. We test an even
74	// stronger restriction, that one store can't shadow another unless the
75	// types of the address fields are identical (where identicalness is
76	// decided by the CSE pass).
77	c := testConfig(t)
78	t1 := c.config.Types.UInt64.PtrTo()
79	t2 := c.config.Types.UInt32.PtrTo()
80	fun := c.Fun("entry",
81		Bloc("entry",
82			Valu("start", OpInitMem, types.TypeMem, 0, nil),
83			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
84			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
85			Valu("addr1", OpAddr, t1, 0, nil, "sb"),
86			Valu("addr2", OpAddr, t2, 0, nil, "sb"),
87			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "start"),
88			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr2", "v", "store1"),
89			Goto("exit")),
90		Bloc("exit",
91			Exit("store2")))
92
93	CheckFunc(fun.f)
94	cse(fun.f)
95	dse(fun.f)
96	CheckFunc(fun.f)
97
98	v := fun.values["store1"]
99	if v.Op == OpCopy {
100		t.Errorf("store %s incorrectly removed", v)
101	}
102}
103
104func TestDeadStoreUnsafe(t *testing.T) {
105	// Make sure a narrow store can't shadow a wider one. The test above
106	// covers the case of two different types, but unsafe pointer casting
107	// can get to a point where the size is changed but type unchanged.
108	c := testConfig(t)
109	ptrType := c.config.Types.UInt64.PtrTo()
110	fun := c.Fun("entry",
111		Bloc("entry",
112			Valu("start", OpInitMem, types.TypeMem, 0, nil),
113			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
114			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
115			Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
116			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Int64, "addr1", "v", "start"), // store 8 bytes
117			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "store1"), // store 1 byte
118			Goto("exit")),
119		Bloc("exit",
120			Exit("store2")))
121
122	CheckFunc(fun.f)
123	cse(fun.f)
124	dse(fun.f)
125	CheckFunc(fun.f)
126
127	v := fun.values["store1"]
128	if v.Op == OpCopy {
129		t.Errorf("store %s incorrectly removed", v)
130	}
131}
132
133func TestDeadStoreSmallStructInit(t *testing.T) {
134	c := testConfig(t)
135	ptrType := c.config.Types.BytePtr
136	typ := types.NewStruct([]*types.Field{
137		types.NewField(src.NoXPos, &types.Sym{Name: "A"}, c.config.Types.Int),
138		types.NewField(src.NoXPos, &types.Sym{Name: "B"}, c.config.Types.Int),
139	})
140	name := c.Temp(typ)
141	fun := c.Fun("entry",
142		Bloc("entry",
143			Valu("start", OpInitMem, types.TypeMem, 0, nil),
144			Valu("sp", OpSP, c.config.Types.Uintptr, 0, nil),
145			Valu("zero", OpConst64, c.config.Types.Int, 0, nil),
146			Valu("v6", OpLocalAddr, ptrType, 0, name, "sp", "start"),
147			Valu("v3", OpOffPtr, ptrType, 8, nil, "v6"),
148			Valu("v22", OpOffPtr, ptrType, 0, nil, "v6"),
149			Valu("zerostore1", OpStore, types.TypeMem, 0, c.config.Types.Int, "v22", "zero", "start"),
150			Valu("zerostore2", OpStore, types.TypeMem, 0, c.config.Types.Int, "v3", "zero", "zerostore1"),
151			Valu("v8", OpLocalAddr, ptrType, 0, name, "sp", "zerostore2"),
152			Valu("v23", OpOffPtr, ptrType, 8, nil, "v8"),
153			Valu("v25", OpOffPtr, ptrType, 0, nil, "v8"),
154			Valu("zerostore3", OpStore, types.TypeMem, 0, c.config.Types.Int, "v25", "zero", "zerostore2"),
155			Valu("zerostore4", OpStore, types.TypeMem, 0, c.config.Types.Int, "v23", "zero", "zerostore3"),
156			Goto("exit")),
157		Bloc("exit",
158			Exit("zerostore4")))
159
160	fun.f.Name = "smallstructinit"
161	CheckFunc(fun.f)
162	cse(fun.f)
163	dse(fun.f)
164	CheckFunc(fun.f)
165
166	v1 := fun.values["zerostore1"]
167	if v1.Op != OpCopy {
168		t.Errorf("dead store not removed")
169	}
170	v2 := fun.values["zerostore2"]
171	if v2.Op != OpCopy {
172		t.Errorf("dead store not removed")
173	}
174}
175