Source file
src/cmd/compile/internal/ssa/merge_conditional_branches_test.go
1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "testing"
10 )
11
12
13 func ARM64Lt(cond, sub, alt string) ctrl {
14 return ctrl{BlockARM64LT, cond, []string{sub, alt}}
15 }
16
17
18 func ARM64Gt(cond, sub, alt string) ctrl {
19 return ctrl{BlockARM64GT, cond, []string{sub, alt}}
20 }
21
22
23 func ARM64Ne(cond, sub, alt string) ctrl {
24 return ctrl{BlockARM64NE, cond, []string{sub, alt}}
25 }
26
27
28 func ARM64Eq(cond, sub, alt string) ctrl {
29 return ctrl{BlockARM64EQ, cond, []string{sub, alt}}
30 }
31
32
33
34
35
36
37
38
39
40
41 func isNewConditionCorrect(b *Block) bool {
42 if b.Kind != BlockARM64LT {
43 return false
44 }
45
46 v := b.Controls[0]
47 if v.Op != OpARM64CCMPconst {
48 return false
49 }
50
51 params := v.AuxArm64ConditionalParams()
52 if params.Cond() != OpARM64GreaterThan {
53 return false
54 }
55 if params.Nzcv() != 1 {
56
57 return false
58 }
59 if imm, ok := params.ConstValue(); !ok || imm != 4 {
60 return false
61 }
62
63 return true
64 }
65
66
67
68
69
70 func containsOpARM64CCMP(b *Block) bool {
71 for _, v := range b.Values {
72 if v.Op == OpARM64CCMP || v.Op == OpARM64CCMPconst {
73 return true
74 }
75 }
76 return false
77 }
78
79
80
81
82
83
84
85
86
87 func TestMergeConditionalBranchesWithoutPointers(t *testing.T) {
88 t.Run("arm64", func(t *testing.T) {
89 c := testConfigArch(t, "arm64")
90 intType := c.config.Types.Int64
91 fun := c.Fun("entry",
92 Bloc("entry",
93 Valu("mem",
94 OpInitMem,
95 types.TypeMem,
96 0, nil,
97 ),
98 Valu("a",
99 OpArg,
100 intType,
101 0, c.Temp(intType),
102 ),
103 Valu("b",
104 OpArg,
105 intType,
106 1, c.Temp(intType),
107 ),
108 Valu("cond1",
109 OpARM64CMPconst,
110 types.TypeFlags,
111 1, nil,
112 "a",
113 ),
114 ARM64Gt("cond1", "second_comparison", "ret_false"),
115 ),
116 Bloc("second_comparison",
117 Valu("cond2",
118 OpARM64CMPconst,
119 types.TypeFlags,
120 4, nil,
121 "b",
122 ),
123 ARM64Lt("cond2", "ret_false", "ret_true"),
124 ),
125 Bloc("ret_true",
126 Valu("const1",
127 OpARM64MOVDconst,
128 intType,
129 1, nil,
130 ),
131 Valu("true_result",
132 OpMakeResult,
133 types.TypeMem,
134 0, nil,
135 "const1", "mem",
136 ),
137 Ret("true_result"),
138 ),
139 Bloc("ret_false",
140 Valu("const0",
141 OpARM64MOVDconst,
142 intType,
143 0, nil,
144 ),
145 Valu("false_result",
146 OpMakeResult,
147 types.TypeMem,
148 0, nil,
149 "const0", "mem",
150 ),
151 Ret("false_result"),
152 ),
153 )
154
155 CheckFunc(fun.f)
156 mergeConditionalBranches(fun.f)
157 CheckFunc(fun.f)
158
159 if len(fun.blocks) != 4 {
160 t.Errorf("Important block was deleted")
161 }
162
163 entryBlock := fun.blocks["entry"]
164 secondBlock := fun.blocks["second_comparison"]
165
166 if secondBlock.Kind != BlockPlain || len(secondBlock.Values) != 0 {
167 t.Errorf("Block with second condition wasn't cleaned")
168 }
169
170 if !isNewConditionCorrect(entryBlock) {
171 t.Errorf("Entry block doesn't contain CCMP opertation")
172 }
173 })
174 }
175
176
177 func TestNoCCMPWithPointerAndMemoryLoad(t *testing.T) {
178 t.Run("arm64", func(t *testing.T) {
179 c := testConfigArch(t, "arm64")
180 intType := c.config.Types.Int64
181 ptrType := c.config.Types.BytePtr
182
183 fun := c.Fun("entry",
184 Bloc("entry",
185 Valu("mem",
186 OpInitMem,
187 types.TypeMem,
188 0, nil,
189 ),
190 Valu("ptr",
191 OpArg,
192 ptrType,
193 0, c.Temp(ptrType),
194 ),
195 Valu("cond1",
196 OpARM64CMPconst,
197 types.TypeFlags,
198 0, nil,
199 "ptr",
200 ),
201 ARM64Ne("cond1", "second_comparison", "ret_false"),
202 ),
203 Bloc("second_comparison",
204 Valu("load",
205 OpLoad,
206 intType,
207 0, nil,
208 "ptr", "mem",
209 ),
210 Valu("cond2",
211 OpARM64CMPconst,
212 types.TypeFlags,
213 3, nil,
214 "load",
215 ),
216 ARM64Eq("cond2", "ret_true", "ret_false"),
217 ),
218 Bloc("ret_true",
219 Valu("const1",
220 OpARM64MOVDconst,
221 intType,
222 1, nil,
223 ),
224 Valu("true_result",
225 OpMakeResult,
226 types.TypeMem,
227 0, nil,
228 "const1", "mem",
229 ),
230 Ret("true_result"),
231 ),
232 Bloc("ret_false",
233 Valu("const0",
234 OpARM64MOVDconst,
235 intType,
236 0, nil,
237 ),
238 Valu("false_result",
239 OpMakeResult,
240 types.TypeMem,
241 0, nil,
242 "const0", "mem",
243 ),
244 Ret("false_result"),
245 ),
246 )
247
248 CheckFunc(fun.f)
249 mergeConditionalBranches(fun.f)
250 CheckFunc(fun.f)
251
252
253 if fun.blocks["second_comparison"] == nil {
254 t.Errorf("Second comparison block was incorrectly removed")
255 }
256
257 entryBlock := fun.blocks["entry"]
258 secondBlock := fun.blocks["second_comparison"]
259
260
261 if containsOpARM64CCMP(entryBlock) {
262 t.Errorf("Entry block contains CCMP operation, but shouldn't due to memory load")
263 }
264
265
266 hasLoad := false
267 for _, v := range secondBlock.Values {
268 if v.Op == OpLoad {
269 hasLoad = true
270 break
271 }
272 }
273 if !hasLoad {
274 t.Errorf("Second comparison block should contain load operation")
275 }
276
277
278 if secondBlock.Kind == BlockPlain {
279 t.Errorf("Block with memory load was incorrectly cleaned")
280 }
281 })
282 }
283
View as plain text