1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "unit_test.h"
17 #include "optimizer/optimizations/adjust_arefs.h"
18
19 namespace panda::compiler {
20 class AdjustRefsTest : public GraphTest {
21 public:
AdjustRefsTest()22 AdjustRefsTest() {}
23 };
24
25 /* One block, continuous chain */
TEST_F(AdjustRefsTest,OneBlockContinuousChain)26 TEST_F(AdjustRefsTest, OneBlockContinuousChain)
27 {
28 auto graph = CreateEmptyFastpathGraph(RUNTIME_ARCH);
29 #ifndef NDEBUG
30 graph->SetLowLevelInstructionsEnabled();
31 #endif
32 GRAPH(graph)
33 {
34 PARAMETER(0, 0).ref();
35 PARAMETER(1, 1).s32();
36 PARAMETER(2, 2).u64();
37 CONSTANT(3, 10).s32();
38
39 BASIC_BLOCK(3, 4, 5)
40 {
41 INST(10, Opcode::Phi).s32().Inputs(1, 40);
42 INST(11, Opcode::LoadArray).u64().Inputs(0, 1);
43 INST(12, Opcode::LoadArray).u64().Inputs(0, 1);
44 INST(13, Opcode::StoreArray).u64().Inputs(0, 1, 2);
45 INST(14, Opcode::StoreArray).u64().Inputs(0, 1, 2);
46 INST(15, Opcode::Compare).b().Inputs(10, 1);
47 INST(19, Opcode::IfImm).CC(CC_NE).Inputs(15).Imm(0);
48 }
49 BASIC_BLOCK(4, 3)
50 {
51 INST(40, Opcode::Add).s32().Inputs(10, 3);
52 }
53 BASIC_BLOCK(5, 1)
54 {
55 INST(50, Opcode::ReturnVoid);
56 }
57 }
58
59 Graph *graph_et = CreateEmptyFastpathGraph(RUNTIME_ARCH);
60 GRAPH(graph_et)
61 {
62 PARAMETER(0, 0).ref();
63 PARAMETER(1, 1).s32();
64 PARAMETER(2, 2).u64();
65 CONSTANT(3, 10).s32();
66
67 BASIC_BLOCK(3, 4, 5)
68 {
69 INST(10, Opcode::Phi).s32().Inputs(1, 40);
70 INST(11, Opcode::AddI).ptr().Inputs(0).Imm(graph->GetRuntime()->GetArrayDataOffset(graph->GetArch()));
71 INST(12, Opcode::Load).u64().Inputs(11, 1);
72 INST(13, Opcode::Load).u64().Inputs(11, 1);
73 INST(14, Opcode::Store).u64().Inputs(11, 1, 2);
74 INST(15, Opcode::Store).u64().Inputs(11, 1, 2);
75 INST(16, Opcode::Compare).b().Inputs(10, 1);
76 INST(19, Opcode::IfImm).CC(CC_NE).Inputs(16).Imm(0);
77 }
78
79 BASIC_BLOCK(4, 3)
80 {
81 INST(40, Opcode::Add).s32().Inputs(10, 3);
82 }
83 BASIC_BLOCK(5, 1)
84 {
85 INST(50, Opcode::ReturnVoid);
86 }
87 }
88
89 ASSERT_TRUE(graph->RunPass<AdjustRefs>());
90
91 GraphChecker(graph).Check();
92 ASSERT_TRUE(GraphComparator().Compare(graph, graph_et));
93 }
94
95 /* One block, broken chain */
TEST_F(AdjustRefsTest,OneBlockBrokenChain)96 TEST_F(AdjustRefsTest, OneBlockBrokenChain)
97 {
98 auto graph = CreateEmptyFastpathGraph(RUNTIME_ARCH);
99 #ifndef NDEBUG
100 graph->SetLowLevelInstructionsEnabled();
101 #endif
102 GRAPH(graph)
103 {
104 PARAMETER(0, 0).ref();
105 PARAMETER(1, 1).s32();
106 PARAMETER(2, 2).u64();
107 CONSTANT(3, 10).s32();
108
109 BASIC_BLOCK(3, 4, 5)
110 {
111 INST(10, Opcode::Phi).s32().Inputs(1, 40);
112 INST(11, Opcode::LoadArray).u64().Inputs(0, 1);
113 INST(12, Opcode::LoadArray).u64().Inputs(0, 1);
114 INST(13, Opcode::SafePoint).NoVregs();
115 INST(14, Opcode::StoreArray).u64().Inputs(0, 1, 2);
116 INST(15, Opcode::StoreArray).u64().Inputs(0, 1, 2);
117 INST(16, Opcode::Compare).b().Inputs(10, 1);
118 INST(19, Opcode::IfImm).CC(CC_NE).Inputs(16).Imm(0);
119 }
120 BASIC_BLOCK(4, 3)
121 {
122 INST(40, Opcode::Add).s32().Inputs(10, 3);
123 }
124 BASIC_BLOCK(5, 1)
125 {
126 INST(50, Opcode::ReturnVoid);
127 }
128 }
129
130 Graph *graph_et = CreateEmptyFastpathGraph(RUNTIME_ARCH);
131 GRAPH(graph_et)
132 {
133 PARAMETER(0, 0).ref();
134 PARAMETER(1, 1).s32();
135 PARAMETER(2, 2).u64();
136 CONSTANT(3, 10).s32();
137
138 BASIC_BLOCK(3, 4, 5)
139 {
140 INST(10, Opcode::Phi).s32().Inputs(1, 40);
141 INST(11, Opcode::AddI).ptr().Inputs(0).Imm(graph->GetRuntime()->GetArrayDataOffset(graph->GetArch()));
142 INST(12, Opcode::Load).u64().Inputs(11, 1);
143 INST(13, Opcode::Load).u64().Inputs(11, 1);
144
145 INST(14, Opcode::SafePoint).NoVregs();
146
147 INST(15, Opcode::AddI).ptr().Inputs(0).Imm(graph->GetRuntime()->GetArrayDataOffset(graph->GetArch()));
148 INST(16, Opcode::Store).u64().Inputs(15, 1, 2);
149 INST(17, Opcode::Store).u64().Inputs(15, 1, 2);
150
151 INST(18, Opcode::Compare).b().Inputs(10, 1);
152 INST(19, Opcode::IfImm).CC(CC_NE).Inputs(18).Imm(0);
153 }
154
155 BASIC_BLOCK(4, 3)
156 {
157 INST(40, Opcode::Add).s32().Inputs(10, 3);
158 }
159 BASIC_BLOCK(5, 1)
160 {
161 INST(50, Opcode::ReturnVoid);
162 }
163 }
164
165 ASSERT_TRUE(graph->RunPass<AdjustRefs>());
166
167 GraphChecker(graph).Check();
168 ASSERT_TRUE(GraphComparator().Compare(graph, graph_et));
169 }
170
171 /* one head, the chain spans across multiple blocks, not broken */
TEST_F(AdjustRefsTest,MultipleBlockContinuousChain)172 TEST_F(AdjustRefsTest, MultipleBlockContinuousChain)
173 {
174 auto graph = CreateEmptyFastpathGraph(RUNTIME_ARCH);
175 #ifndef NDEBUG
176 graph->SetLowLevelInstructionsEnabled();
177 #endif
178 GRAPH(graph)
179 {
180 PARAMETER(0, 0).ref();
181 PARAMETER(1, 1).s32();
182 PARAMETER(2, 2).u64();
183 CONSTANT(3, 10).s32();
184
185 BASIC_BLOCK(3, 4, 10)
186 {
187 INST(10, Opcode::Phi).s32().Inputs(1, 90);
188 INST(11, Opcode::LoadArray).u64().Inputs(0, 1);
189 INST(15, Opcode::Compare).b().Inputs(10, 1);
190 INST(19, Opcode::IfImm).CC(CC_NE).Inputs(15).Imm(0);
191 }
192 BASIC_BLOCK(4, 5, 6)
193 {
194 INST(41, Opcode::Compare).b().Inputs(10, 1);
195 INST(42, Opcode::IfImm).CC(CC_NE).Inputs(41).Imm(0);
196 }
197 BASIC_BLOCK(5, 9)
198 {
199 INST(51, Opcode::LoadArray).u64().Inputs(0, 1);
200 }
201 BASIC_BLOCK(6, 9)
202 {
203 INST(61, Opcode::LoadArray).u64().Inputs(0, 1);
204 }
205 BASIC_BLOCK(9, 3)
206 {
207 INST(90, Opcode::Add).s32().Inputs(10, 3);
208 }
209 BASIC_BLOCK(10, 1)
210 {
211 INST(100, Opcode::ReturnVoid);
212 }
213 }
214
215 Graph *graph_et = CreateEmptyFastpathGraph(RUNTIME_ARCH);
216 GRAPH(graph_et)
217 {
218 PARAMETER(0, 0).ref();
219 PARAMETER(1, 1).s32();
220 PARAMETER(2, 2).u64();
221 CONSTANT(3, 10).s32();
222 BASIC_BLOCK(3, 4, 10)
223 {
224 INST(10, Opcode::Phi).s32().Inputs(1, 90);
225 INST(11, Opcode::AddI).ptr().Inputs(0).Imm(graph->GetRuntime()->GetArrayDataOffset(graph->GetArch()));
226 INST(12, Opcode::Load).u64().Inputs(11, 1);
227 INST(15, Opcode::Compare).b().Inputs(10, 1);
228 INST(19, Opcode::IfImm).CC(CC_NE).Inputs(15).Imm(0);
229 }
230 BASIC_BLOCK(4, 5, 6)
231 {
232 INST(41, Opcode::Compare).b().Inputs(10, 1);
233 INST(42, Opcode::IfImm).CC(CC_NE).Inputs(41).Imm(0);
234 }
235 BASIC_BLOCK(5, 9)
236 {
237 INST(51, Opcode::Load).u64().Inputs(11, 1);
238 }
239 BASIC_BLOCK(6, 9)
240 {
241 INST(61, Opcode::Load).u64().Inputs(11, 1);
242 }
243 BASIC_BLOCK(9, 3)
244 {
245 INST(90, Opcode::Add).s32().Inputs(10, 3);
246 }
247 BASIC_BLOCK(10, 1)
248 {
249 INST(100, Opcode::ReturnVoid);
250 }
251 }
252
253 ASSERT_TRUE(graph->RunPass<AdjustRefs>());
254
255 GraphChecker(graph).Check();
256 ASSERT_TRUE(GraphComparator().Compare(graph, graph_et));
257 }
258
259 /* one head, the chain spans across multiple blocks,
260 * broken in one of the dominated basic blocks */
TEST_F(AdjustRefsTest,MultipleBlockBrokenChain)261 TEST_F(AdjustRefsTest, MultipleBlockBrokenChain)
262 {
263 auto graph = CreateEmptyFastpathGraph(RUNTIME_ARCH);
264 #ifndef NDEBUG
265 graph->SetLowLevelInstructionsEnabled();
266 #endif
267 GRAPH(graph)
268 {
269 PARAMETER(0, 0).ref();
270 PARAMETER(1, 1).s32();
271 PARAMETER(2, 2).u64();
272 CONSTANT(3, 10).s32();
273
274 BASIC_BLOCK(3, 4, 10)
275 {
276 INST(10, Opcode::Phi).s32().Inputs(1, 90);
277 INST(11, Opcode::LoadArray).u64().Inputs(0, 1);
278 INST(15, Opcode::Compare).b().Inputs(10, 1);
279 INST(19, Opcode::IfImm).CC(CC_NE).Inputs(15).Imm(0);
280 }
281 BASIC_BLOCK(4, 5, 6)
282 {
283 INST(41, Opcode::Compare).b().Inputs(10, 1);
284 INST(42, Opcode::IfImm).CC(CC_NE).Inputs(41).Imm(0);
285 }
286 BASIC_BLOCK(5, 9)
287 {
288 INST(51, Opcode::LoadArray).u64().Inputs(0, 1);
289 }
290 BASIC_BLOCK(6, 9)
291 {
292 INST(13, Opcode::SafePoint).NoVregs();
293 INST(61, Opcode::LoadArray).u64().Inputs(0, 1);
294 }
295 BASIC_BLOCK(9, 3)
296 {
297 INST(90, Opcode::Add).s32().Inputs(10, 3);
298 }
299 BASIC_BLOCK(10, 1)
300 {
301 INST(100, Opcode::ReturnVoid);
302 }
303 }
304
305 Graph *graph_et = CreateEmptyFastpathGraph(RUNTIME_ARCH);
306 GRAPH(graph_et)
307 {
308 PARAMETER(0, 0).ref();
309 PARAMETER(1, 1).s32();
310 PARAMETER(2, 2).u64();
311 CONSTANT(3, 10).s32();
312 BASIC_BLOCK(3, 4, 10)
313 {
314 INST(10, Opcode::Phi).s32().Inputs(1, 90);
315 INST(11, Opcode::AddI).ptr().Inputs(0).Imm(graph->GetRuntime()->GetArrayDataOffset(graph->GetArch()));
316 INST(12, Opcode::Load).u64().Inputs(11, 1);
317 INST(15, Opcode::Compare).b().Inputs(10, 1);
318 INST(19, Opcode::IfImm).CC(CC_NE).Inputs(15).Imm(0);
319 }
320 BASIC_BLOCK(4, 5, 6)
321 {
322 INST(41, Opcode::Compare).b().Inputs(10, 1);
323 INST(42, Opcode::IfImm).CC(CC_NE).Inputs(41).Imm(0);
324 }
325 BASIC_BLOCK(5, 9)
326 {
327 INST(51, Opcode::Load).u64().Inputs(11, 1);
328 }
329 BASIC_BLOCK(6, 9)
330 {
331 INST(13, Opcode::SafePoint).NoVregs();
332 INST(61, Opcode::LoadArray).u64().Inputs(0, 1);
333 }
334 BASIC_BLOCK(9, 3)
335 {
336 INST(90, Opcode::Add).s32().Inputs(10, 3);
337 }
338 BASIC_BLOCK(10, 1)
339 {
340 INST(100, Opcode::ReturnVoid);
341 }
342 }
343
344 ASSERT_TRUE(graph->RunPass<AdjustRefs>());
345
346 GraphChecker(graph).Check();
347 ASSERT_TRUE(GraphComparator().Compare(graph, graph_et));
348 }
349
350 } // namespace panda::compiler
351