1 /*
2 * Copyright (c) 2021-2024 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/ir/graph_cloner.h"
18 #include "optimizer/optimizations/memory_coalescing.h"
19 #include "optimizer/optimizations/scheduler.h"
20 #include "optimizer/optimizations/regalloc/reg_alloc.h"
21
22 namespace ark::compiler {
23 class MemoryCoalescingTest : public GraphTest {
24 #ifndef NDEBUG
25 public:
MemoryCoalescingTest()26 MemoryCoalescingTest()
27 {
28 // GraphChecker hack: LowLevel instructions may appear only after Lowering pass:
29 GetGraph()->SetLowLevelInstructionsEnabled();
30 }
31 #endif
32 };
33
34 // NOLINTBEGIN(readability-magic-numbers)
TEST_F(MemoryCoalescingTest,ImmidiateLoads)35 TEST_F(MemoryCoalescingTest, ImmidiateLoads)
36 {
37 // Coalescing is supported only for aarch64
38 if (GetGraph()->GetArch() != Arch::AARCH64) {
39 return;
40 }
41 GRAPH(GetGraph())
42 {
43 CONSTANT(0U, 0x2aU).s64();
44 BASIC_BLOCK(2U, -1L)
45 {
46 INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
47 INST(3U, Opcode::NewArray).ref().Inputs(44U, 0U).TypeId(77U);
48 INST(41U, Opcode::SaveState).Inputs(3U).SrcVregs({7U});
49 INST(42U, Opcode::NullCheck).ref().Inputs(3U, 41U);
50 INST(225U, Opcode::LoadArrayI).s64().Inputs(42U).Imm(0x0U);
51 INST(227U, Opcode::LoadArrayI).s64().Inputs(42U).Imm(0x1U);
52
53 INST(51U, Opcode::Add).s64().Inputs(225U, 227U);
54 INST(229U, Opcode::StoreArrayI).s64().Inputs(42U, 51U).Imm(0x0U);
55 INST(230U, Opcode::StoreArrayI).s64().Inputs(42U, 51U).Imm(0x1U);
56 INST(40U, Opcode::Return).s64().Inputs(51U);
57 }
58 }
59 Graph *optGraph = CreateEmptyGraph();
60 GRAPH(optGraph)
61 {
62 CONSTANT(0U, 0x2aU).s64();
63 BASIC_BLOCK(2U, -1L)
64 {
65 INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
66 INST(3U, Opcode::NewArray).ref().Inputs(44U, 0U).TypeId(77U);
67 INST(41U, Opcode::SaveState).Inputs(3U).SrcVregs({7U});
68 INST(42U, Opcode::NullCheck).ref().Inputs(3U, 41U);
69 INST(231U, Opcode::LoadArrayPairI).s64().Inputs(42U).Imm(0x0U);
70 INST(232U, Opcode::LoadPairPart).s64().Inputs(231U).Imm(0x0U);
71 INST(233U, Opcode::LoadPairPart).s64().Inputs(231U).Imm(0x1U);
72
73 INST(51U, Opcode::Add).s64().Inputs(232U, 233U);
74 INST(234U, Opcode::StoreArrayPairI).s64().Inputs(42U, 51U, 51U).Imm(0x0U);
75 INST(40U, Opcode::Return).s64().Inputs(51U);
76 }
77 }
78 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
79 GraphChecker(GetGraph()).Check();
80 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
81 }
82
SRC_GRAPH(LoopLoadCoalescing,Graph * graph)83 SRC_GRAPH(LoopLoadCoalescing, Graph *graph)
84 {
85 GRAPH(graph)
86 {
87 PARAMETER(5U, 0U).ref();
88 CONSTANT(6U, 0x0U).s64();
89 BASIC_BLOCK(2U, 3U)
90 {
91 INST(35U, Opcode::SaveState).Inputs(5U).SrcVregs({1U});
92 INST(36U, Opcode::NullCheck).ref().Inputs(5U, 35U);
93 }
94 BASIC_BLOCK(3U, 3U, 7U)
95 {
96 INST(9U, Opcode::Phi).s32().Inputs({{2U, 6U}, {3U, 64U}});
97 INST(10U, Opcode::Phi).s64().Inputs({{2U, 6U}, {3U, 28U}});
98 INST(19U, Opcode::LoadArray).s64().Inputs(36U, 9U);
99 INST(63U, Opcode::AddI).s32().Inputs(9U).Imm(0x1U);
100 INST(26U, Opcode::LoadArray).s64().Inputs(36U, 63U);
101 INST(27U, Opcode::Add).s64().Inputs(26U, 19U);
102 INST(28U, Opcode::Add).s64().Inputs(27U, 10U);
103 INST(64U, Opcode::AddI).s32().Inputs(9U).Imm(0x2U);
104 INST(31U, Opcode::IfImm).SrcType(DataType::INT32).CC(CC_LT).Imm(0x4U).Inputs(64U);
105 }
106 BASIC_BLOCK(7U, -1L)
107 {
108 INST(33U, Opcode::Return).s32().Inputs(28U);
109 }
110 }
111 }
112
OUT_GRAPH(LoopLoadCoalescing,Graph * graph)113 OUT_GRAPH(LoopLoadCoalescing, Graph *graph)
114 {
115 GRAPH(graph)
116 {
117 PARAMETER(5U, 0U).ref();
118 CONSTANT(6U, 0x0U).s64();
119 BASIC_BLOCK(2U, 3U)
120 {
121 INST(35U, Opcode::SaveState).Inputs(5U).SrcVregs({1U});
122 INST(36U, Opcode::NullCheck).ref().Inputs(5U, 35U);
123 }
124 BASIC_BLOCK(3U, 3U, 7U)
125 {
126 INST(9U, Opcode::Phi).s32().Inputs({{2U, 6U}, {3U, 64U}});
127 INST(10U, Opcode::Phi).s64().Inputs({{2U, 6U}, {3U, 28U}});
128 INST(65U, Opcode::LoadArrayPair).s64().Inputs(36U, 9U);
129 INST(66U, Opcode::LoadPairPart).s64().Inputs(65U).Imm(0x0U);
130 INST(67U, Opcode::LoadPairPart).s64().Inputs(65U).Imm(0x1U);
131 INST(63U, Opcode::AddI).s32().Inputs(9U).Imm(0x1U);
132 INST(27U, Opcode::Add).s64().Inputs(67U, 66U);
133 INST(28U, Opcode::Add).s64().Inputs(27U, 10U);
134 INST(64U, Opcode::AddI).s32().Inputs(9U).Imm(0x2U);
135 INST(31U, Opcode::IfImm).SrcType(DataType::INT32).CC(CC_LT).Imm(0x4U).Inputs(64U);
136 }
137 BASIC_BLOCK(7U, -1L)
138 {
139 INST(33U, Opcode::Return).s32().Inputs(28U);
140 }
141 }
142 }
143
TEST_F(MemoryCoalescingTest,LoopLoadCoalescing)144 TEST_F(MemoryCoalescingTest, LoopLoadCoalescing)
145 {
146 // Coalescing is supported only for aarch64
147 if (GetGraph()->GetArch() != Arch::AARCH64) {
148 return;
149 }
150 src_graph::LoopLoadCoalescing::CREATE(GetGraph());
151 Graph *optGraph = CreateEmptyGraph();
152 out_graph::LoopLoadCoalescing::CREATE(optGraph);
153 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
154 GraphChecker(GetGraph()).Check();
155 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
156 }
157
SRC_GRAPH(LoopStoreCoalescing,Graph * graph)158 SRC_GRAPH(LoopStoreCoalescing, Graph *graph)
159 {
160 GRAPH(graph)
161 {
162 PARAMETER(0U, 0U).ref();
163 CONSTANT(4U, 0x0U).s64();
164 CONSTANT(5U, 0x1U).s64();
165 BASIC_BLOCK(2U, 3U)
166 {
167 INST(3U, Opcode::LenArray).s32().Inputs(0U);
168 }
169 BASIC_BLOCK(3U, 3U, 4U)
170 {
171 INST(6U, Opcode::Phi).s32().Inputs({{2U, 4U}, {3U, 34U}});
172 INST(7U, Opcode::Phi).s32().Inputs({{2U, 5U}, {3U, 24U}});
173 INST(8U, Opcode::Phi).s32().Inputs({{2U, 5U}, {3U, 25U}});
174 INST(17U, Opcode::StoreArray).s32().Inputs(0U, 6U, 7U);
175 INST(33U, Opcode::AddI).s32().Inputs(6U).Imm(0x1U);
176 INST(23U, Opcode::StoreArray).s32().Inputs(0U, 33U, 8U);
177 INST(24U, Opcode::Add).s32().Inputs(7U, 8U);
178 INST(25U, Opcode::Add).s32().Inputs(8U, 24U);
179 INST(34U, Opcode::AddI).s32().Inputs(6U).Imm(0x2U);
180 INST(35U, Opcode::If).SrcType(DataType::INT32).CC(CC_LT).Inputs(34U, 3U);
181 }
182 BASIC_BLOCK(4U, -1L)
183 {
184 INST(29U, Opcode::ReturnVoid).v0id();
185 }
186 }
187 }
188
OUT_GRAPH(LoopStoreCoalescing,Graph * graph)189 OUT_GRAPH(LoopStoreCoalescing, Graph *graph)
190 {
191 GRAPH(graph)
192 {
193 PARAMETER(0U, 0U).ref();
194 CONSTANT(4U, 0x0U).s64();
195 CONSTANT(5U, 0x1U).s64();
196 BASIC_BLOCK(2U, 3U)
197 {
198 INST(3U, Opcode::LenArray).s32().Inputs(0U);
199 }
200 BASIC_BLOCK(3U, 3U, 4U)
201 {
202 INST(6U, Opcode::Phi).s32().Inputs({{2U, 4U}, {3U, 34U}});
203 INST(7U, Opcode::Phi).s32().Inputs({{2U, 5U}, {3U, 24U}});
204 INST(8U, Opcode::Phi).s32().Inputs({{2U, 5U}, {3U, 25U}});
205 INST(33U, Opcode::AddI).s32().Inputs(6U).Imm(0x1U);
206 INST(36U, Opcode::StoreArrayPair).s32().Inputs(0U, 6U, 7U, 8U);
207 INST(24U, Opcode::Add).s32().Inputs(7U, 8U);
208 INST(25U, Opcode::Add).s32().Inputs(8U, 24U);
209 INST(34U, Opcode::AddI).s32().Inputs(6U).Imm(0x2U);
210 INST(35U, Opcode::If).SrcType(DataType::INT32).CC(CC_LT).Inputs(34U, 3U);
211 }
212 BASIC_BLOCK(4U, -1L)
213 {
214 INST(29U, Opcode::ReturnVoid).v0id();
215 }
216 }
217 }
218
TEST_F(MemoryCoalescingTest,LoopStoreCoalescing)219 TEST_F(MemoryCoalescingTest, LoopStoreCoalescing)
220 {
221 // Coalescing is supported only for aarch64
222 if (GetGraph()->GetArch() != Arch::AARCH64) {
223 return;
224 }
225 src_graph::LoopStoreCoalescing::CREATE(GetGraph());
226 Graph *optGraph = CreateEmptyGraph();
227 out_graph::LoopStoreCoalescing::CREATE(optGraph);
228 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
229 GraphChecker(GetGraph()).Check();
230 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
231 }
232
TEST_F(MemoryCoalescingTest,AliasedAccess)233 TEST_F(MemoryCoalescingTest, AliasedAccess)
234 {
235 // Coalescing is supported only for aarch64
236 if (GetGraph()->GetArch() != Arch::AARCH64) {
237 return;
238 }
239 GRAPH(GetGraph())
240 {
241 PARAMETER(0U, 0U).ref();
242 BASIC_BLOCK(2U, -1L)
243 {
244 INST(26U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
245 INST(28U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
246 INST(21U, Opcode::Add).s64().Inputs(28U, 26U);
247 INST(22U, Opcode::Return).s64().Inputs(21U);
248 }
249 }
250 Graph *optGraph = CreateEmptyGraph();
251 GRAPH(optGraph)
252 {
253 PARAMETER(0U, 0U).ref();
254 BASIC_BLOCK(2U, -1L)
255 {
256 INST(29U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
257 INST(30U, Opcode::LoadPairPart).s64().Inputs(29U).Imm(0x0U);
258 INST(31U, Opcode::LoadPairPart).s64().Inputs(29U).Imm(0x1U);
259 INST(21U, Opcode::Add).s64().Inputs(31U, 30U);
260 INST(22U, Opcode::Return).s64().Inputs(21U);
261 }
262 }
263 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
264 GraphChecker(GetGraph()).Check();
265 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
266 }
267
TEST_F(MemoryCoalescingTest,OnlySingleCoalescing)268 TEST_F(MemoryCoalescingTest, OnlySingleCoalescing)
269 {
270 // Coalescing is supported only for aarch64
271 if (GetGraph()->GetArch() != Arch::AARCH64) {
272 return;
273 }
274 GRAPH(GetGraph())
275 {
276 PARAMETER(0U, 0U).ref();
277 BASIC_BLOCK(2U, -1L)
278 {
279 INST(26U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
280 INST(28U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
281
282 INST(30U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
283 INST(21U, Opcode::Add).s64().Inputs(28U, 26U);
284 INST(22U, Opcode::Add).s64().Inputs(30U, 21U);
285 INST(23U, Opcode::Return).s64().Inputs(22U);
286 }
287 }
288 Graph *optGraph = CreateEmptyGraph();
289 GRAPH(optGraph)
290 {
291 PARAMETER(0U, 0U).ref();
292 BASIC_BLOCK(2U, -1L)
293 {
294 INST(31U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
295 INST(33U, Opcode::LoadPairPart).s64().Inputs(31U).Imm(0x0U);
296 INST(32U, Opcode::LoadPairPart).s64().Inputs(31U).Imm(0x1U);
297
298 INST(30U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
299 INST(21U, Opcode::Add).s64().Inputs(32U, 33U);
300 INST(22U, Opcode::Add).s64().Inputs(30U, 21U);
301 INST(23U, Opcode::Return).s64().Inputs(22U);
302 }
303 }
304 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
305 GraphChecker(GetGraph()).Check();
306 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
307 }
308
TEST_F(MemoryCoalescingTest,PseudoParts)309 TEST_F(MemoryCoalescingTest, PseudoParts)
310 {
311 // Coalescing is supported only for aarch64
312 if (GetGraph()->GetArch() != Arch::AARCH64) {
313 return;
314 }
315 GRAPH(GetGraph())
316 {
317 PARAMETER(0U, 0U).ref();
318 BASIC_BLOCK(2U, -1L)
319 {
320 INST(1U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
321 INST(2U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
322
323 INST(3U, Opcode::StoreArrayI).s64().Inputs(0U, 2U).Imm(0x0U);
324 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 1U).Imm(0x1U);
325 INST(5U, Opcode::ReturnVoid).v0id();
326 }
327 }
328 Graph *optGraph = CreateEmptyGraph();
329 GRAPH(optGraph)
330 {
331 PARAMETER(0U, 0U).ref();
332 BASIC_BLOCK(2U, -1L)
333 {
334 INST(6U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
335 INST(7U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x0U);
336 INST(8U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x1U);
337
338 INST(9U, Opcode::StoreArrayPairI).s64().Inputs(0U, 8U, 7U).Imm(0x0U);
339 INST(5U, Opcode::ReturnVoid).v0id();
340 }
341 }
342 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
343 GetGraph()->RunPass<Scheduler>();
344 RegAlloc(GetGraph());
345 GraphChecker(GetGraph()).Check();
346 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
347 }
348
SRC_GRAPH(UnalignedStores,Graph * graph)349 SRC_GRAPH(UnalignedStores, Graph *graph)
350 {
351 GRAPH(graph)
352 {
353 PARAMETER(0U, 0U).ref();
354 PARAMETER(1U, 1U).s64();
355 PARAMETER(2U, 2U).s64();
356 PARAMETER(3U, 3U).s64();
357 BASIC_BLOCK(2U, -1L)
358 {
359 INST(4U, Opcode::AddI).s32().Inputs(1U).Imm(0x4U);
360 INST(5U, Opcode::StoreArray).s32().Inputs(0U, 4U, 2U);
361 INST(6U, Opcode::AddI).s32().Inputs(1U).Imm(0x5U);
362 INST(7U, Opcode::StoreArray).s32().Inputs(0U, 6U, 3U);
363
364 INST(8U, Opcode::StoreArray).s32().Inputs(0U, 4U, 3U);
365 INST(9U, Opcode::AddI).s32().Inputs(4U).Imm(0x1U);
366 INST(10U, Opcode::StoreArray).s32().Inputs(0U, 9U, 2U);
367 INST(11U, Opcode::ReturnVoid).v0id();
368 }
369 }
370 }
371
OUT_GRAPH(UnalignedStores,Graph * graph)372 OUT_GRAPH(UnalignedStores, Graph *graph)
373 {
374 GRAPH(graph)
375 {
376 PARAMETER(0U, 0U).ref();
377 PARAMETER(1U, 1U).s64();
378 PARAMETER(2U, 2U).s64();
379 PARAMETER(3U, 3U).s64();
380 BASIC_BLOCK(2U, -1L)
381 {
382 INST(4U, Opcode::AddI).s32().Inputs(1U).Imm(0x4U);
383 INST(6U, Opcode::AddI).s32().Inputs(1U).Imm(0x5U);
384 INST(12U, Opcode::StoreArrayPair).s32().Inputs(0U, 1U, 2U, 3U).Imm(0x4U);
385
386 INST(9U, Opcode::AddI).s32().Inputs(4U).Imm(0x1U);
387 INST(13U, Opcode::StoreArrayPair).s32().Inputs(0U, 1U, 3U, 2U).Imm(0x4U);
388 INST(11U, Opcode::ReturnVoid).v0id();
389 }
390 }
391 }
392
TEST_F(MemoryCoalescingTest,UnalignedStores)393 TEST_F(MemoryCoalescingTest, UnalignedStores)
394 {
395 // Coalescing is supported only for aarch64
396 if (GetGraph()->GetArch() != Arch::AARCH64) {
397 return;
398 }
399 src_graph::UnalignedStores::CREATE(GetGraph());
400 Graph *optGraph = CreateEmptyGraph();
401 out_graph::UnalignedStores::CREATE(optGraph);
402 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
403 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(true));
404 GraphChecker(GetGraph()).Check();
405 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
406
407 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
408 GraphChecker(GetGraph()).Check();
409 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
410 }
411
TEST_F(MemoryCoalescingTest,NoAlignmentTestI)412 TEST_F(MemoryCoalescingTest, NoAlignmentTestI)
413 {
414 // Coalescing is supported only for aarch64
415 if (GetGraph()->GetArch() != Arch::AARCH64) {
416 return;
417 }
418 GRAPH(GetGraph())
419 {
420 PARAMETER(0U, 0U).ref();
421 BASIC_BLOCK(2U, -1L)
422 {
423 INST(1U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x2U);
424 INST(2U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
425 INST(3U, Opcode::Add).s64().Inputs(2U, 1U);
426 INST(4U, Opcode::Return).s64().Inputs(3U);
427 }
428 }
429 Graph *optGraph = CreateEmptyGraph();
430 GRAPH(optGraph)
431 {
432 PARAMETER(0U, 0U).ref();
433 BASIC_BLOCK(2U, -1L)
434 {
435 INST(5U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x1U);
436 INST(6U, Opcode::LoadPairPart).s64().Inputs(5U).Imm(0x0U);
437 INST(7U, Opcode::LoadPairPart).s64().Inputs(5U).Imm(0x1U);
438 INST(3U, Opcode::Add).s64().Inputs(6U, 7U);
439 INST(4U, Opcode::Return).s64().Inputs(3U);
440 }
441 }
442 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
443 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(true));
444 GraphChecker(GetGraph()).Check();
445 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
446
447 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
448 GraphChecker(GetGraph()).Check();
449 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
450 }
451
TEST_F(MemoryCoalescingTest,StoresRoundedByLoads)452 TEST_F(MemoryCoalescingTest, StoresRoundedByLoads)
453 {
454 // Coalescing is supported only for aarch64
455 if (GetGraph()->GetArch() != Arch::AARCH64) {
456 return;
457 }
458 GRAPH(GetGraph())
459 {
460 PARAMETER(0U, 0U).ref();
461 PARAMETER(1U, 1U).s64();
462 PARAMETER(2U, 2U).s64();
463 BASIC_BLOCK(2U, -1L)
464 {
465 INST(3U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x2U);
466 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 1U).Imm(0x2U);
467 INST(5U, Opcode::StoreArrayI).s64().Inputs(0U, 2U).Imm(0x3U);
468 INST(6U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x3U);
469 INST(7U, Opcode::Add).s64().Inputs(3U, 6U);
470 INST(8U, Opcode::Return).s64().Inputs(7U);
471 }
472 }
473 Graph *optGraph = CreateEmptyGraph();
474 GRAPH(optGraph)
475 {
476 PARAMETER(0U, 0U).ref();
477 PARAMETER(1U, 1U).s64();
478 PARAMETER(2U, 2U).s64();
479 BASIC_BLOCK(2U, -1L)
480 {
481 INST(3U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x2U);
482 INST(9U, Opcode::StoreArrayPairI).s64().Inputs(0U, 1U, 2U).Imm(0x2U);
483 INST(6U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x3U);
484 INST(7U, Opcode::Add).s64().Inputs(3U, 6U);
485 INST(8U, Opcode::Return).s64().Inputs(7U);
486 }
487 }
488 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
489 GraphChecker(GetGraph()).Check();
490 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
491 }
492
TEST_F(MemoryCoalescingTest,LoadsRoundedByStores)493 TEST_F(MemoryCoalescingTest, LoadsRoundedByStores)
494 {
495 // Coalescing is supported only for aarch64
496 if (GetGraph()->GetArch() != Arch::AARCH64) {
497 return;
498 }
499 GRAPH(GetGraph())
500 {
501 PARAMETER(0U, 0U).ref();
502 PARAMETER(1U, 1U).s64();
503 PARAMETER(2U, 2U).s64();
504 BASIC_BLOCK(2U, -1L)
505 {
506 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 1U).Imm(0x3U);
507 INST(3U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x2U);
508 INST(6U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x3U);
509 INST(5U, Opcode::StoreArrayI).s64().Inputs(0U, 2U).Imm(0x2U);
510 INST(7U, Opcode::Add).s64().Inputs(3U, 6U);
511 INST(8U, Opcode::Return).s64().Inputs(7U);
512 }
513 }
514 Graph *optGraph = CreateEmptyGraph();
515 GRAPH(optGraph)
516 {
517 PARAMETER(0U, 0U).ref();
518 PARAMETER(1U, 1U).s64();
519 PARAMETER(2U, 2U).s64();
520 BASIC_BLOCK(2U, -1L)
521 {
522 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 1U).Imm(0x3U);
523 INST(9U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x2U);
524 INST(10U, Opcode::LoadPairPart).s64().Inputs(9U).Imm(0x0U);
525 INST(11U, Opcode::LoadPairPart).s64().Inputs(9U).Imm(0x1U);
526 INST(5U, Opcode::StoreArrayI).s64().Inputs(0U, 2U).Imm(0x2U);
527 INST(7U, Opcode::Add).s64().Inputs(10U, 11U);
528 INST(8U, Opcode::Return).s64().Inputs(7U);
529 }
530 }
531 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
532 GraphChecker(GetGraph()).Check();
533 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
534 }
535
SRC_GRAPH(UnalignedInLoop,Graph * graph)536 SRC_GRAPH(UnalignedInLoop, Graph *graph)
537 {
538 GRAPH(graph)
539 {
540 PARAMETER(0U, 0U).s32();
541 PARAMETER(1U, 1U).s32();
542 CONSTANT(3U, 0xaU).s64();
543 BASIC_BLOCK(2U, 3U)
544 {
545 INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
546 INST(6U, Opcode::NewArray).ref().Inputs(44U, 3U).TypeId(77U);
547 }
548 BASIC_BLOCK(3U, 3U, 4U)
549 {
550 INST(7U, Opcode::Phi).s32().Inputs({{2U, 0U}, {3U, 33U}});
551 INST(19U, Opcode::StoreArray).s32().Inputs(6U, 7U, 7U);
552 INST(33U, Opcode::AddI).s32().Inputs(7U).Imm(0x1U);
553 INST(25U, Opcode::StoreArray).s32().Inputs(6U, 33U, 7U);
554 INST(34U, Opcode::If).SrcType(DataType::INT32).CC(CC_GT).Inputs(1U, 33U);
555 }
556 BASIC_BLOCK(4U, -1L)
557 {
558 INST(29U, Opcode::Return).s32().Inputs(33U);
559 }
560 }
561 }
562
OUT_GRAPH(UnalignedInLoop,Graph * graph)563 OUT_GRAPH(UnalignedInLoop, Graph *graph)
564 {
565 GRAPH(graph)
566 {
567 PARAMETER(0U, 0U).s32();
568 PARAMETER(1U, 1U).s32();
569 CONSTANT(3U, 0xaU).s64();
570 BASIC_BLOCK(2U, 3U)
571 {
572 INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
573 INST(6U, Opcode::NewArray).ref().Inputs(44U, 3U).TypeId(77U);
574 }
575 BASIC_BLOCK(3U, 3U, 4U)
576 {
577 INST(7U, Opcode::Phi).s32().Inputs({{2U, 0U}, {3U, 33U}});
578 INST(33U, Opcode::AddI).s32().Inputs(7U).Imm(0x1U);
579 INST(35U, Opcode::StoreArrayPair).s32().Inputs(6U, 7U, 7U, 7U);
580 INST(34U, Opcode::If).SrcType(DataType::INT32).CC(CC_GT).Inputs(1U, 33U);
581 }
582 BASIC_BLOCK(4U, -1L)
583 {
584 INST(29U, Opcode::Return).s32().Inputs(33U);
585 }
586 }
587 }
588
TEST_F(MemoryCoalescingTest,UnalignedInLoop)589 TEST_F(MemoryCoalescingTest, UnalignedInLoop)
590 {
591 // Coalescing is supported only for aarch64
592 if (GetGraph()->GetArch() != Arch::AARCH64) {
593 return;
594 }
595 src_graph::UnalignedInLoop::CREATE(GetGraph());
596 Graph *optGraph = CreateEmptyGraph();
597 out_graph::UnalignedInLoop::CREATE(optGraph);
598 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
599 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(true));
600 GraphChecker(GetGraph()).Check();
601 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
602
603 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
604 GraphChecker(GetGraph()).Check();
605 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
606 }
607
TEST_F(MemoryCoalescingTest,IndexInference)608 TEST_F(MemoryCoalescingTest, IndexInference)
609 {
610 // Coalescing is supported only for aarch64
611 if (GetGraph()->GetArch() != Arch::AARCH64) {
612 return;
613 }
614 GRAPH(GetGraph())
615 {
616 PARAMETER(0U, 0U).ref();
617 PARAMETER(1U, 1U).s64();
618 BASIC_BLOCK(2U, -1L)
619 {
620 INST(6U, Opcode::AddI).s32().Inputs(1U).Imm(0x1U);
621 INST(7U, Opcode::LoadArray).s32().Inputs(0U, 1U);
622 INST(8U, Opcode::LoadArray).s32().Inputs(0U, 6U);
623 INST(9U, Opcode::StoreArray).s32().Inputs(0U, 1U, 7U);
624 INST(10U, Opcode::StoreArray).s32().Inputs(0U, 6U, 8U);
625 INST(11U, Opcode::ReturnVoid).v0id();
626 }
627 }
628 Graph *optGraph = CreateEmptyGraph();
629 GRAPH(optGraph)
630 {
631 PARAMETER(0U, 0U).ref();
632 PARAMETER(1U, 1U).s64();
633 BASIC_BLOCK(2U, -1L)
634 {
635 INST(6U, Opcode::AddI).s32().Inputs(1U).Imm(0x1U);
636 INST(12U, Opcode::LoadArrayPair).s32().Inputs(0U, 1U);
637 INST(14U, Opcode::LoadPairPart).s32().Inputs(12U).Imm(0x0U);
638 INST(13U, Opcode::LoadPairPart).s32().Inputs(12U).Imm(0x1U);
639 INST(15U, Opcode::StoreArrayPair).s32().Inputs(0U, 1U, 14U, 13U);
640 INST(11U, Opcode::ReturnVoid).v0id();
641 }
642 }
643 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
644 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(true));
645 GraphChecker(GetGraph()).Check();
646 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
647
648 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
649 GraphChecker(GetGraph()).Check();
650 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
651 }
652
TEST_F(MemoryCoalescingTest,SimplePlaceFinding)653 TEST_F(MemoryCoalescingTest, SimplePlaceFinding)
654 {
655 // Coalescing is supported only for aarch64
656 if (GetGraph()->GetArch() != Arch::AARCH64) {
657 return;
658 }
659 GRAPH(GetGraph())
660 {
661 PARAMETER(0U, 0U).ref();
662 PARAMETER(1U, 1U).s64();
663 BASIC_BLOCK(2U, -1L)
664 {
665 INST(7U, Opcode::LoadArray).s32().Inputs(0U, 1U);
666 INST(6U, Opcode::SubI).s32().Inputs(1U).Imm(1U);
667 INST(8U, Opcode::LoadArray).s32().Inputs(0U, 6U);
668 INST(9U, Opcode::Add).s32().Inputs(7U, 8U);
669 INST(11U, Opcode::Return).s32().Inputs(9U);
670 }
671 }
672 Graph *optGraph = CreateEmptyGraph();
673 GRAPH(optGraph)
674 {
675 PARAMETER(0U, 0U).ref();
676 PARAMETER(1U, 1U).s64();
677 BASIC_BLOCK(2U, -1L)
678 {
679 INST(6U, Opcode::SubI).s32().Inputs(1U).Imm(1U);
680 INST(12U, Opcode::LoadArrayPair).s32().Inputs(0U, 6U);
681 INST(14U, Opcode::LoadPairPart).s32().Inputs(12U).Imm(0x0U);
682 INST(13U, Opcode::LoadPairPart).s32().Inputs(12U).Imm(0x1U);
683 INST(9U, Opcode::Add).s32().Inputs(13U, 14U);
684 INST(11U, Opcode::Return).s32().Inputs(9U);
685 }
686 }
687 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
688 GraphChecker(GetGraph()).Check();
689 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
690 }
691
TEST_F(MemoryCoalescingTest,ObjectAccessesCoalescing)692 TEST_F(MemoryCoalescingTest, ObjectAccessesCoalescing)
693 {
694 // Coalescing is supported only for aarch64
695 if (GetGraph()->GetArch() != Arch::AARCH64) {
696 return;
697 }
698 GRAPH(GetGraph())
699 {
700 PARAMETER(0U, 0U).ref();
701 CONSTANT(1U, 0x2U).s64();
702 BASIC_BLOCK(2U, -1L)
703 {
704 INST(50U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
705 INST(44U, Opcode::LoadAndInitClass).ref().Inputs(50U).TypeId(68U);
706 INST(4U, Opcode::NewArray).ref().Inputs(44U, 1U, 50U).TypeId(88U);
707 INST(38U, Opcode::LoadArrayI).ref().Inputs(0U).Imm(0x0U);
708 INST(40U, Opcode::LoadArrayI).ref().Inputs(0U).Imm(0x1U);
709 INST(41U, Opcode::StoreArrayI).ref().Inputs(4U, 38U).Imm(0x0U);
710 INST(42U, Opcode::StoreArrayI).ref().Inputs(4U, 40U).Imm(0x1U);
711 INST(27U, Opcode::ReturnVoid).v0id();
712 }
713 }
714 Graph *optGraph = CreateEmptyGraph();
715 GRAPH(optGraph)
716 {
717 PARAMETER(0U, 0U).ref();
718 CONSTANT(1U, 0x2U).s64();
719 BASIC_BLOCK(2U, -1L)
720 {
721 INST(50U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
722 INST(444U, Opcode::LoadAndInitClass).ref().Inputs(50U).TypeId(68U);
723 INST(4U, Opcode::NewArray).ref().Inputs(444U, 1U, 50U).TypeId(88U);
724 INST(43U, Opcode::LoadArrayPairI).ref().Inputs(0U).Imm(0x0U);
725 INST(45U, Opcode::LoadPairPart).ref().Inputs(43U).Imm(0x0U);
726 INST(44U, Opcode::LoadPairPart).ref().Inputs(43U).Imm(0x1U);
727 INST(46U, Opcode::StoreArrayPairI).ref().Inputs(4U, 45U, 44U).Imm(0x0U);
728 INST(27U, Opcode::ReturnVoid).v0id();
729 }
730 }
731 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
732 g_options.SetCompilerMemoryCoalescingObjects(false);
733 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(true));
734 GraphChecker(GetGraph()).Check();
735 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
736
737 g_options.SetCompilerMemoryCoalescingObjects(true);
738 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(true));
739 GraphChecker(GetGraph()).Check();
740 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
741 }
742
SRC_GRAPH(AllowedVolatileReordering,Graph * graph)743 SRC_GRAPH(AllowedVolatileReordering, Graph *graph)
744 {
745 GRAPH(graph)
746 {
747 CONSTANT(0U, 0x2aU).s64();
748 BASIC_BLOCK(2U, -1L)
749 {
750 INST(4U, Opcode::SaveState).SrcVregs({});
751 INST(5U, Opcode::LoadAndInitClass).ref().Inputs(4U).TypeId(0U);
752
753 INST(3U, Opcode::NewArray).ref().Inputs(5U, 0U).TypeId(77U);
754 // Can reorder Volatile Store (v226) and Normal Load (v227)
755 INST(225U, Opcode::LoadArrayI).s64().Inputs(3U).Imm(0x0U);
756 INST(226U, Opcode::StoreStatic).s64().Volatile().Inputs(5U, 225U).TypeId(103U);
757 INST(227U, Opcode::LoadArrayI).s64().Inputs(3U).Imm(0x1U);
758
759 INST(51U, Opcode::Add).s64().Inputs(225U, 227U);
760 // Can reorder Normal Store (v229) and Volatile Load (v230)
761 INST(229U, Opcode::StoreArrayI).s64().Inputs(3U, 51U).Imm(0x0U);
762 INST(230U, Opcode::LoadStatic).s64().Inputs(5U).Volatile().TypeId(107U);
763 INST(231U, Opcode::StoreArrayI).s64().Inputs(3U, 230U).Imm(0x1U);
764 INST(40U, Opcode::Return).s64().Inputs(51U);
765 }
766 }
767 }
768
OUT_GRAPH(AllowedVolatileReordering,Graph * graph)769 OUT_GRAPH(AllowedVolatileReordering, Graph *graph)
770 {
771 GRAPH(graph)
772 {
773 CONSTANT(0U, 0x2aU).s64();
774 BASIC_BLOCK(2U, -1L)
775 {
776 INST(4U, Opcode::SaveState).SrcVregs({});
777 INST(5U, Opcode::LoadAndInitClass).ref().Inputs(4U).TypeId(0U);
778
779 INST(3U, Opcode::NewArray).ref().Inputs(5U, 0U).TypeId(77U);
780 INST(232U, Opcode::LoadArrayPairI).s64().Inputs(3U).Imm(0x0U);
781 INST(234U, Opcode::LoadPairPart).s64().Inputs(232U).Imm(0x0U);
782 INST(233U, Opcode::LoadPairPart).s64().Inputs(232U).Imm(0x1U);
783 INST(226U, Opcode::StoreStatic).s64().Volatile().Inputs(5U, 234U).TypeId(103U);
784
785 INST(51U, Opcode::Add).s64().Inputs(234U, 233U);
786 INST(230U, Opcode::LoadStatic).s64().Inputs(5U).Volatile().TypeId(107U);
787 INST(235U, Opcode::StoreArrayPairI).s64().Inputs(3U, 51U, 230U).Imm(0x0U);
788 INST(40U, Opcode::Return).s64().Inputs(51U);
789 }
790 }
791 }
792
TEST_F(MemoryCoalescingTest,AllowedVolatileReordering)793 TEST_F(MemoryCoalescingTest, AllowedVolatileReordering)
794 {
795 // Coalescing is supported only for aarch64
796 if (GetGraph()->GetArch() != Arch::AARCH64) {
797 return;
798 }
799 src_graph::AllowedVolatileReordering::CREATE(GetGraph());
800 Graph *optGraph = CreateEmptyGraph();
801 out_graph::AllowedVolatileReordering::CREATE(optGraph);
802 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
803 GraphChecker(GetGraph()).Check();
804 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
805 }
806
SRC_GRAPH(AllowedVolatileReordering2,Graph * graph)807 SRC_GRAPH(AllowedVolatileReordering2, Graph *graph)
808 {
809 GRAPH(graph)
810 {
811 CONSTANT(0U, 0x2aU).s64();
812 BASIC_BLOCK(2U, -1L)
813 {
814 INST(4U, Opcode::SaveState).SrcVregs({});
815 INST(5U, Opcode::LoadAndInitClass).ref().Inputs(4U).TypeId(0U);
816
817 INST(3U, Opcode::NewArray).ref().Inputs(5U, 0U).TypeId(77U);
818 // We can reorder v225 and v226 but not v226 and v227
819 INST(225U, Opcode::LoadArrayI).s64().Inputs(3U).Imm(0x0U);
820 INST(226U, Opcode::LoadStatic).s64().Inputs(5U).Volatile().TypeId(103U);
821 INST(227U, Opcode::LoadArrayI).s64().Inputs(3U).Imm(0x1U);
822
823 INST(51U, Opcode::Add).s64().Inputs(225U, 227U);
824 // We can reorder v230 and v231 but not v229 and v230
825 INST(229U, Opcode::StoreArrayI).s64().Inputs(3U, 51U).Imm(0x0U);
826 INST(230U, Opcode::StoreStatic).s64().Inputs(5U).Volatile().Inputs(226U).TypeId(105U);
827 INST(231U, Opcode::StoreArrayI).s64().Inputs(3U, 51U).Imm(0x1U);
828 INST(40U, Opcode::Return).s64().Inputs(51U);
829 }
830 }
831 }
832
OUT_GRAPH(AllowedVolatileReordering2,Graph * graph)833 OUT_GRAPH(AllowedVolatileReordering2, Graph *graph)
834 {
835 GRAPH(graph)
836 {
837 CONSTANT(0U, 0x2aU).s64();
838 BASIC_BLOCK(2U, -1L)
839 {
840 INST(4U, Opcode::SaveState).SrcVregs({});
841 INST(5U, Opcode::LoadAndInitClass).ref().Inputs(4U).TypeId(0U);
842
843 INST(3U, Opcode::NewArray).ref().Inputs(5U, 0U).TypeId(77U);
844 INST(226U, Opcode::LoadStatic).s64().Inputs(5U).Volatile().TypeId(103U);
845 INST(235U, Opcode::LoadArrayPairI).s64().Inputs(3U).Imm(0x0U);
846 INST(237U, Opcode::LoadPairPart).s64().Inputs(235U).Imm(0x0U);
847 INST(236U, Opcode::LoadPairPart).s64().Inputs(235U).Imm(0x1U);
848
849 INST(51U, Opcode::Add).s64().Inputs(237U, 236U);
850 INST(238U, Opcode::StoreArrayPairI).s64().Inputs(3U, 51U, 51U).Imm(0x0U);
851 INST(230U, Opcode::StoreStatic).s64().Inputs(5U).Volatile().Inputs(226U).TypeId(105U);
852 INST(40U, Opcode::Return).s64().Inputs(51U);
853 }
854 }
855 }
856
TEST_F(MemoryCoalescingTest,AllowedVolatileReordering2)857 TEST_F(MemoryCoalescingTest, AllowedVolatileReordering2)
858 {
859 // Coalescing is supported only for aarch64
860 if (GetGraph()->GetArch() != Arch::AARCH64) {
861 return;
862 }
863 src_graph::AllowedVolatileReordering2::CREATE(GetGraph());
864 Graph *optGraph = CreateEmptyGraph();
865 out_graph::AllowedVolatileReordering2::CREATE(optGraph);
866 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
867 GraphChecker(GetGraph()).Check();
868 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
869 }
870
SRC_GRAPH(UnrolledLoop,Graph * graph)871 SRC_GRAPH(UnrolledLoop, Graph *graph)
872 {
873 GRAPH(graph)
874 {
875 PARAMETER(0U, 0U).s64();
876 PARAMETER(1U, 1U).ref();
877 CONSTANT(3U, 0x2aU).s64();
878 CONSTANT(4U, 0x0U).s64();
879 BASIC_BLOCK(2U, 3U, 4U)
880 {
881 INST(50U, Opcode::SaveState).Inputs(1U).SrcVregs({0U});
882 INST(44U, Opcode::LoadAndInitClass).ref().Inputs(50U).TypeId(68U);
883 INST(2U, Opcode::NewArray).ref().Inputs(44U, 3U, 50U).TypeId(77U);
884 INST(10U, Opcode::IfImm).SrcType(DataType::INT64).CC(CC_LE).Imm(0x0U).Inputs(0U);
885 }
886 BASIC_BLOCK(3U, 3U, 4U)
887 {
888 INST(11U, Opcode::Phi).s32().Inputs({{2U, 4U}, {3U, 17U}});
889 INST(12U, Opcode::LoadArray).s32().Inputs(1U, 11U);
890 INST(13U, Opcode::StoreArray).s32().Inputs(2U, 11U, 12U);
891 INST(14U, Opcode::AddI).s32().Inputs(11U).Imm(1U);
892
893 INST(15U, Opcode::LoadArray).s32().Inputs(1U, 14U);
894 INST(16U, Opcode::StoreArray).s32().Inputs(2U, 14U, 15U);
895 INST(17U, Opcode::AddI).s32().Inputs(11U).Imm(2U);
896
897 INST(30U, Opcode::If).SrcType(DataType::INT32).CC(CC_GE).Inputs(17U, 3U);
898 }
899 BASIC_BLOCK(4U, -1L)
900 {
901 INST(40U, Opcode::ReturnVoid);
902 }
903 }
904 }
905
OUT_GRAPH(UnrolledLoop,Graph * graph)906 OUT_GRAPH(UnrolledLoop, Graph *graph)
907 {
908 GRAPH(graph)
909 {
910 PARAMETER(0U, 0U).s64();
911 PARAMETER(1U, 1U).ref();
912 CONSTANT(3U, 0x2aU).s64();
913 CONSTANT(4U, 0x0U).s64();
914 BASIC_BLOCK(2U, 3U, 4U)
915 {
916 INST(50U, Opcode::SaveState).Inputs(1U).SrcVregs({0U});
917 INST(444U, Opcode::LoadAndInitClass).ref().Inputs(50U).TypeId(68U);
918 INST(2U, Opcode::NewArray).ref().Inputs(444U, 3U, 50U).TypeId(77U);
919 INST(10U, Opcode::IfImm).SrcType(DataType::INT64).CC(CC_LE).Imm(0x0U).Inputs(0U);
920 }
921 BASIC_BLOCK(3U, 3U, 4U)
922 {
923 INST(11U, Opcode::Phi).s32().Inputs({{2U, 4U}, {3U, 17U}});
924 INST(44U, Opcode::LoadArrayPair).s32().Inputs(1U, 11U);
925 INST(46U, Opcode::LoadPairPart).s32().Inputs(44U).Imm(0x0U);
926 INST(45U, Opcode::LoadPairPart).s32().Inputs(44U).Imm(0x1U);
927 INST(14U, Opcode::AddI).s32().Inputs(11U).Imm(1U);
928
929 INST(47U, Opcode::StoreArrayPair).s32().Inputs(2U, 11U, 46U, 45U);
930 INST(17U, Opcode::AddI).s32().Inputs(11U).Imm(2U);
931
932 INST(30U, Opcode::If).SrcType(DataType::INT32).CC(CC_GE).Inputs(17U, 3U);
933 }
934 BASIC_BLOCK(4U, -1L)
935 {
936 INST(40U, Opcode::ReturnVoid);
937 }
938 }
939 }
940
TEST_F(MemoryCoalescingTest,UnrolledLoop)941 TEST_F(MemoryCoalescingTest, UnrolledLoop)
942 {
943 // Coalescing is supported only for aarch64
944 if (GetGraph()->GetArch() != Arch::AARCH64) {
945 return;
946 }
947 src_graph::UnrolledLoop::CREATE(GetGraph());
948 Graph *optGraph = CreateEmptyGraph();
949 out_graph::UnrolledLoop::CREATE(optGraph);
950 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
951 GraphChecker(GetGraph()).Check();
952 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
953 }
954
SRC_GRAPH(CoalescingOverSaveState,Graph * graph)955 SRC_GRAPH(CoalescingOverSaveState, Graph *graph)
956 {
957 GRAPH(graph)
958 {
959 PARAMETER(0U, 0U).ref();
960 BASIC_BLOCK(2U, -1L)
961 {
962 INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({6U});
963 INST(2U, Opcode::NullCheck).ref().Inputs(0U, 1U);
964
965 INST(41U, Opcode::SaveState).Inputs(0U).SrcVregs({6U});
966 INST(43U, Opcode::LenArray).s32().Inputs(2U);
967 INST(241U, Opcode::BoundsCheckI).s32().Inputs(43U, 41U).Imm(0x0U);
968 INST(242U, Opcode::LoadArrayI).s64().Inputs(2U).Imm(0x0U);
969
970 INST(47U, Opcode::SaveState).Inputs(242U, 0U).SrcVregs({3U, 6U});
971 INST(49U, Opcode::LenArray).s32().Inputs(2U);
972 INST(244U, Opcode::BoundsCheckI).s32().Inputs(49U, 47U).Imm(0x1U);
973 INST(245U, Opcode::LoadArrayI).s64().Inputs(2U).Imm(0x1U);
974
975 INST(53U, Opcode::Add).s64().Inputs(242U, 245U);
976 INST(40U, Opcode::Return).s64().Inputs(53U);
977 }
978 }
979 }
980
OUT_GRAPH(CoalescingOverSaveState,Graph * graph)981 OUT_GRAPH(CoalescingOverSaveState, Graph *graph)
982 {
983 GRAPH(graph)
984 {
985 PARAMETER(0U, 0U).ref();
986
987 BASIC_BLOCK(2U, -1L)
988 {
989 INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({6U});
990 INST(2U, Opcode::NullCheck).ref().Inputs(0U, 1U);
991
992 INST(41U, Opcode::SaveState).Inputs(0U).SrcVregs({6U});
993 INST(43U, Opcode::LenArray).s32().Inputs(2U);
994 INST(241U, Opcode::BoundsCheckI).s32().Inputs(43U, 41U).Imm(0x0U);
995
996 INST(246U, Opcode::LoadArrayPairI).s64().Inputs(2U).Imm(0x0U);
997 INST(248U, Opcode::LoadPairPart).s64().Inputs(246U).Imm(0x0U);
998 INST(247U, Opcode::LoadPairPart).s64().Inputs(246U).Imm(0x1U);
999
1000 INST(47U, Opcode::SaveState).Inputs(248U, 0U).SrcVregs({3U, 6U});
1001 INST(49U, Opcode::LenArray).s32().Inputs(2U);
1002 INST(244U, Opcode::BoundsCheckI).s32().Inputs(49U, 47U).Imm(0x1U);
1003
1004 INST(53U, Opcode::Add).s64().Inputs(248U, 247U);
1005 INST(40U, Opcode::Return).s64().Inputs(53U);
1006 }
1007 }
1008 }
1009
TEST_F(MemoryCoalescingTest,CoalescingOverSaveState)1010 TEST_F(MemoryCoalescingTest, CoalescingOverSaveState)
1011 {
1012 // Coalescing is supported only for aarch64
1013 if (GetGraph()->GetArch() != Arch::AARCH64) {
1014 return;
1015 }
1016 src_graph::CoalescingOverSaveState::CREATE(GetGraph());
1017 GraphChecker(GetGraph()).Check();
1018 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1019 GraphChecker(GetGraph()).Check();
1020
1021 Graph *optGraph = CreateEmptyGraph();
1022 out_graph::CoalescingOverSaveState::CREATE(optGraph);
1023 GraphChecker(optGraph).Check();
1024 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
1025 }
1026
TEST_F(MemoryCoalescingTest,AlignmentTest)1027 TEST_F(MemoryCoalescingTest, AlignmentTest)
1028 {
1029 // Coalescing is supported only for aarch64
1030 if (GetGraph()->GetArch() != Arch::AARCH64) {
1031 return;
1032 }
1033 GRAPH(GetGraph())
1034 {
1035 PARAMETER(0U, 0U).ref();
1036 BASIC_BLOCK(2U, -1L)
1037 {
1038 INST(26U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x2U);
1039 INST(28U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1040 INST(21U, Opcode::Add).s64().Inputs(28U, 26U);
1041 INST(22U, Opcode::Return).s64().Inputs(21U);
1042 }
1043 }
1044 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1045 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
1046 GraphChecker(GetGraph()).Check();
1047 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
1048 }
1049
TEST_F(MemoryCoalescingTest,AliasedStore)1050 TEST_F(MemoryCoalescingTest, AliasedStore)
1051 {
1052 // Coalescing is supported only for aarch64
1053 if (GetGraph()->GetArch() != Arch::AARCH64) {
1054 return;
1055 }
1056 GRAPH(GetGraph())
1057 {
1058 PARAMETER(0U, 0U).ref();
1059 PARAMETER(1U, 1U).s64();
1060 PARAMETER(2U, 2U).s64();
1061 BASIC_BLOCK(2U, -1L)
1062 {
1063 INST(26U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
1064 INST(13U, Opcode::StoreArray).s64().Inputs(0U, 1U, 2U);
1065 INST(28U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x5U);
1066 INST(29U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1067 INST(21U, Opcode::Add).s64().Inputs(28U, 26U);
1068 INST(24U, Opcode::Add).s64().Inputs(21U, 29U);
1069 INST(22U, Opcode::Return).s64().Inputs(24U);
1070 }
1071 }
1072 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1073 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
1074 GraphChecker(GetGraph()).Check();
1075 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
1076 }
1077
TEST_F(MemoryCoalescingTest,TypeCheck)1078 TEST_F(MemoryCoalescingTest, TypeCheck)
1079 {
1080 GRAPH(GetGraph())
1081 {
1082 PARAMETER(0U, 0U).ref();
1083 PARAMETER(1U, 1U).s64();
1084 BASIC_BLOCK(2U, -1L)
1085 {
1086 INST(6U, Opcode::AddI).s32().Inputs(1U).Imm(0x1U);
1087 INST(7U, Opcode::LoadArray).s8().Inputs(0U, 1U);
1088 INST(8U, Opcode::LoadArray).s8().Inputs(0U, 6U);
1089 INST(9U, Opcode::LoadArrayI).s16().Inputs(0U).Imm(0x4U);
1090 INST(10U, Opcode::LoadArrayI).s16().Inputs(0U).Imm(0x5U);
1091 INST(11U, Opcode::StoreArray).s16().Inputs(0U, 1U, 9U);
1092 INST(12U, Opcode::StoreArray).s16().Inputs(0U, 6U, 10U);
1093 INST(13U, Opcode::StoreArrayI).s8().Inputs(0U, 7U).Imm(0x4U);
1094 INST(14U, Opcode::StoreArrayI).s8().Inputs(0U, 8U).Imm(0x5U);
1095 INST(15U, Opcode::ReturnVoid).v0id();
1096 }
1097 }
1098 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1099 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
1100 GraphChecker(GetGraph()).Check();
1101 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
1102 }
1103
TEST_F(MemoryCoalescingTest,ProhibitedVolatileReordering)1104 TEST_F(MemoryCoalescingTest, ProhibitedVolatileReordering)
1105 {
1106 // Coalescing is supported only for aarch64
1107 if (GetGraph()->GetArch() != Arch::AARCH64) {
1108 return;
1109 }
1110 GRAPH(GetGraph())
1111 {
1112 CONSTANT(0U, 0x2aU).s64();
1113 BASIC_BLOCK(2U, -1L)
1114 {
1115 INST(4U, Opcode::SaveState).SrcVregs({});
1116 INST(5U, Opcode::LoadAndInitClass).ref().Inputs(4U).TypeId(0U);
1117
1118 INST(3U, Opcode::NewArray).ref().Inputs(5U, 0U).TypeId(77U);
1119 INST(225U, Opcode::LoadArrayI).s64().Inputs(3U).Imm(0x0U);
1120 // v50 is needed to prevent reordering v225 with v226
1121 INST(50U, Opcode::Add).s64().Inputs(225U, 225U);
1122 INST(226U, Opcode::LoadStatic).s64().Inputs(5U).Volatile().TypeId(103U);
1123 INST(227U, Opcode::LoadArrayI).s64().Inputs(3U).Imm(0x1U);
1124
1125 INST(51U, Opcode::Add).s64().Inputs(50U, 227U);
1126 INST(229U, Opcode::StoreArrayI).s64().Inputs(3U, 51U).Imm(0x0U);
1127 INST(230U, Opcode::StoreStatic).s64().Inputs(5U).Volatile().Inputs(226U).TypeId(105U);
1128 // v51 is needed to prevent reordering v231 and v230
1129 INST(52U, Opcode::Add).s64().Inputs(50U, 51U);
1130 INST(231U, Opcode::StoreArrayI).s64().Inputs(3U, 52U).Imm(0x1U);
1131 INST(40U, Opcode::Return).s64().Inputs(51U);
1132 }
1133 }
1134 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1135 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
1136 GraphChecker(GetGraph()).Check();
1137 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
1138 }
1139
TEST_F(MemoryCoalescingTest,LoweringDominance)1140 TEST_F(MemoryCoalescingTest, LoweringDominance)
1141 {
1142 // Coalescing is supported only for aarch64
1143 if (GetGraph()->GetArch() != Arch::AARCH64) {
1144 return;
1145 }
1146 GRAPH(GetGraph())
1147 {
1148 PARAMETER(0U, 0U).ref();
1149 PARAMETER(1U, 1U).s64();
1150 BASIC_BLOCK(2U, -1L)
1151 {
1152 INST(8U, Opcode::SubI).s32().Inputs(1U).Imm(1U);
1153
1154 INST(9U, Opcode::LoadArray).s32().Inputs(0U, 1U);
1155 INST(10U, Opcode::ShlI).s32().Inputs(9U).Imm(24U);
1156 INST(16U, Opcode::StoreArray).s32().Inputs(0U, 8U, 10U);
1157 INST(11U, Opcode::AShrI).s32().Inputs(9U).Imm(28U);
1158
1159 INST(12U, Opcode::AddI).s64().Inputs(1U).Imm(1U);
1160 INST(13U, Opcode::LoadArray).s32().Inputs(0U, 12U);
1161
1162 INST(14U, Opcode::Add).s32().Inputs(10U, 11U);
1163 INST(15U, Opcode::Return).s32().Inputs(14U);
1164 }
1165 }
1166 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1167 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(false));
1168 GraphChecker(GetGraph()).Check();
1169 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
1170 }
1171
TEST_F(MemoryCoalescingTest,LoweringDominance2)1172 TEST_F(MemoryCoalescingTest, LoweringDominance2)
1173 {
1174 // Coalescing is supported only for aarch64
1175 if (GetGraph()->GetArch() != Arch::AARCH64) {
1176 return;
1177 }
1178 GRAPH(GetGraph())
1179 {
1180 PARAMETER(0U, 0U).ref();
1181 PARAMETER(1U, 1U).ref();
1182 PARAMETER(2U, 2U).ref();
1183 PARAMETER(3U, 3U).s64();
1184 BASIC_BLOCK(2U, -1L)
1185 {
1186 INST(8U, Opcode::SubI).s32().Inputs(3U).Imm(1U);
1187
1188 INST(9U, Opcode::LoadArrayI).s32().Inputs(0U).Imm(0x0U);
1189 INST(10U, Opcode::StoreArray).s32().Inputs(1U, 8U, 9U);
1190
1191 INST(11U, Opcode::LoadArrayI).s32().Inputs(0U).Imm(0x1U);
1192 INST(12U, Opcode::StoreArray).s32().Inputs(2U, 8U, 11U);
1193
1194 INST(15U, Opcode::Return).s32().Inputs(3U);
1195 }
1196 }
1197 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1198 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
1199 GraphChecker(GetGraph()).Check();
1200 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
1201 }
1202
TEST_F(MemoryCoalescingTest,CoalescingLoadsOverSaveState)1203 TEST_F(MemoryCoalescingTest, CoalescingLoadsOverSaveState)
1204 {
1205 // Coalescing is supported only for aarch64
1206 if (GetGraph()->GetArch() != Arch::AARCH64) {
1207 return;
1208 }
1209 GRAPH(GetGraph())
1210 {
1211 PARAMETER(0U, 0U).ref();
1212 PARAMETER(1U, 1U).s64();
1213 BASIC_BLOCK(2U, -1L)
1214 {
1215 INST(9U, Opcode::LoadArray).ref().Inputs(0U, 1U);
1216 INST(10U, Opcode::SaveState).SrcVregs({9U});
1217 INST(11U, Opcode::AddI).s64().Inputs(1U).Imm(1U);
1218 INST(12U, Opcode::LoadArray).ref().Inputs(0U, 11U);
1219 INST(13U, Opcode::SaveState).SrcVregs({9U, 12U});
1220 INST(15U, Opcode::Return).s32().Inputs(1U);
1221 }
1222 }
1223 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1224 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
1225 GraphChecker(GetGraph()).Check();
1226 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
1227 }
1228
TEST_F(MemoryCoalescingTest,CoalescingPhiAsUser)1229 TEST_F(MemoryCoalescingTest, CoalescingPhiAsUser)
1230 {
1231 // Coalescing is supported only for aarch64
1232 if (GetGraph()->GetArch() != Arch::AARCH64) {
1233 return;
1234 }
1235 GRAPH(GetGraph())
1236 {
1237 PARAMETER(0U, 0U).ref();
1238 PARAMETER(1U, 1U).ref();
1239 PARAMETER(2U, 2U).s32();
1240 PARAMETER(3U, 3U).s32();
1241 BASIC_BLOCK(2U, 3U, 2U)
1242 {
1243 INST(9U, Opcode::Phi).s32().Inputs({{0U, 3U}, {2U, 10U}});
1244 INST(10U, Opcode::LoadArray).s32().Inputs(0U, 9U);
1245 INST(11U, Opcode::AddI).s32().Inputs(9U).Imm(1U);
1246 INST(12U, Opcode::LoadArray).s32().Inputs(0U, 11U);
1247 INST(18U, Opcode::IfImm).SrcType(DataType::INT32).CC(CC_EQ).Imm(0U).Inputs(12U);
1248 }
1249 BASIC_BLOCK(3U, -1L)
1250 {
1251 INST(20U, Opcode::Return).s32().Inputs(2U);
1252 }
1253 }
1254 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
1255 GraphChecker(GetGraph()).Check();
1256 }
1257
TEST_F(MemoryCoalescingTest,NestedLoadCoalescing)1258 TEST_F(MemoryCoalescingTest, NestedLoadCoalescing)
1259 {
1260 // Coalescing is supported only for aarch64
1261 if (GetGraph()->GetArch() != Arch::AARCH64) {
1262 return;
1263 }
1264 GRAPH(GetGraph())
1265 {
1266 PARAMETER(0U, 0U).ref();
1267 BASIC_BLOCK(2U, -1L)
1268 {
1269 INST(26U, Opcode::LoadArrayI).ref().Inputs(0U).Imm(0x0U);
1270 INST(28U, Opcode::LoadArrayI).ref().Inputs(0U).Imm(0x1U);
1271
1272 INST(30U, Opcode::LoadArrayI).s64().Inputs(26U).Imm(0x0U);
1273 INST(31U, Opcode::LoadArrayI).s64().Inputs(26U).Imm(0x1U);
1274 INST(32U, Opcode::LoadArrayI).s64().Inputs(28U).Imm(0x0U);
1275
1276 INST(21U, Opcode::Add).s64().Inputs(30U, 31U);
1277 INST(22U, Opcode::Add).s64().Inputs(21U, 32U);
1278 INST(23U, Opcode::Return).s64().Inputs(22U);
1279 }
1280 }
1281 Graph *optGraph = CreateEmptyGraph();
1282 GRAPH(optGraph)
1283 {
1284 PARAMETER(0U, 0U).ref();
1285 BASIC_BLOCK(2U, -1L)
1286 {
1287 INST(31U, Opcode::LoadArrayPairI).ref().Inputs(0U).Imm(0x0U);
1288 INST(32U, Opcode::LoadPairPart).ref().Inputs(31U).Imm(0x0U);
1289 INST(33U, Opcode::LoadPairPart).ref().Inputs(31U).Imm(0x1U);
1290
1291 INST(34U, Opcode::LoadArrayPairI).s64().Inputs(32U).Imm(0x0U);
1292 INST(35U, Opcode::LoadPairPart).s64().Inputs(34U).Imm(0x0U);
1293 INST(36U, Opcode::LoadPairPart).s64().Inputs(34U).Imm(0x1U);
1294 INST(30U, Opcode::LoadArrayI).s64().Inputs(33U).Imm(0x0U);
1295
1296 INST(21U, Opcode::Add).s64().Inputs(35U, 36U);
1297 INST(22U, Opcode::Add).s64().Inputs(21U, 30U);
1298 INST(23U, Opcode::Return).s64().Inputs(22U);
1299 }
1300 }
1301 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1302 GraphChecker(GetGraph()).Check();
1303 }
1304
TEST_F(MemoryCoalescingTest,OnlySingleCoalescingOverSafePoint)1305 TEST_F(MemoryCoalescingTest, OnlySingleCoalescingOverSafePoint)
1306 {
1307 // Coalescing is supported only for aarch64
1308 if (GetGraph()->GetArch() != Arch::AARCH64) {
1309 return;
1310 }
1311 GRAPH(GetGraph())
1312 {
1313 PARAMETER(0U, 0U).ref();
1314 BASIC_BLOCK(2U, -1L)
1315 {
1316 INST(26U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
1317 INST(27U, Opcode::SafePoint).NoVregs();
1318 INST(28U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1319
1320 INST(30U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1321 INST(21U, Opcode::Add).s64().Inputs(28U, 26U);
1322 INST(22U, Opcode::Add).s64().Inputs(30U, 21U);
1323 INST(23U, Opcode::Return).s64().Inputs(22U);
1324 }
1325 }
1326 Graph *optGraph = CreateEmptyGraph();
1327 GRAPH(optGraph)
1328 {
1329 PARAMETER(0U, 0U).ref();
1330 BASIC_BLOCK(2U, -1L)
1331 {
1332 INST(31U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
1333 INST(33U, Opcode::LoadPairPart).s64().Inputs(31U).Imm(0x0U);
1334 INST(32U, Opcode::LoadPairPart).s64().Inputs(31U).Imm(0x1U);
1335 INST(27U, Opcode::SafePoint).Inputs(0U).SrcVregs({VirtualRegister::BRIDGE});
1336
1337 INST(30U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1338 INST(21U, Opcode::Add).s64().Inputs(32U, 33U);
1339 INST(22U, Opcode::Add).s64().Inputs(30U, 21U);
1340 INST(23U, Opcode::Return).s64().Inputs(22U);
1341 }
1342 }
1343 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1344 GraphChecker(GetGraph()).Check();
1345 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
1346 }
1347
TEST_F(MemoryCoalescingTest,PseudoPartsOverSafePoints)1348 TEST_F(MemoryCoalescingTest, PseudoPartsOverSafePoints)
1349 {
1350 // Coalescing is supported only for aarch64
1351 if (GetGraph()->GetArch() != Arch::AARCH64) {
1352 return;
1353 }
1354 GRAPH(GetGraph())
1355 {
1356 PARAMETER(0U, 0U).ref();
1357 BASIC_BLOCK(2U, -1L)
1358 {
1359 INST(1U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
1360 INST(27U, Opcode::SafePoint).NoVregs();
1361 INST(2U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1362
1363 INST(3U, Opcode::StoreArrayI).s64().Inputs(0U, 2U).Imm(0x0U);
1364 INST(28U, Opcode::SafePoint).NoVregs();
1365 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 1U).Imm(0x1U);
1366 INST(5U, Opcode::ReturnVoid).v0id();
1367 }
1368 }
1369 Graph *optGraph = CreateEmptyGraph();
1370 GRAPH(optGraph)
1371 {
1372 PARAMETER(0U, 0U).ref();
1373 BASIC_BLOCK(2U, -1L)
1374 {
1375 INST(6U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
1376 INST(7U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x0U);
1377 INST(8U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x1U);
1378 INST(27U, Opcode::SafePoint).Inputs(0U).SrcVregs({VirtualRegister::BRIDGE});
1379
1380 INST(9U, Opcode::StoreArrayPairI).s64().Inputs(0U, 8U, 7U).Imm(0x0U);
1381 INST(28U, Opcode::SafePoint).NoVregs();
1382 INST(5U, Opcode::ReturnVoid).v0id();
1383 }
1384 }
1385 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1386 GraphChecker(GetGraph()).Check();
1387 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
1388 }
1389
TEST_F(MemoryCoalescingTest,OnlySingleCoalescingOverSaveState)1390 TEST_F(MemoryCoalescingTest, OnlySingleCoalescingOverSaveState)
1391 {
1392 // Coalescing is supported only for aarch64
1393 if (GetGraph()->GetArch() != Arch::AARCH64) {
1394 return;
1395 }
1396 GRAPH(GetGraph())
1397 {
1398 PARAMETER(0U, 0U).ref();
1399 BASIC_BLOCK(2U, -1L)
1400 {
1401 INST(26U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
1402 INST(2U, Opcode::SaveState).NoVregs();
1403 INST(28U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1404
1405 INST(30U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1406 INST(21U, Opcode::Add).s64().Inputs(28U, 26U);
1407 INST(22U, Opcode::Add).s64().Inputs(30U, 21U);
1408 INST(23U, Opcode::Return).s64().Inputs(22U);
1409 }
1410 }
1411 Graph *optGraph = CreateEmptyGraph();
1412 GRAPH(optGraph)
1413 {
1414 PARAMETER(0U, 0U).ref();
1415 BASIC_BLOCK(2U, -1L)
1416 {
1417 INST(31U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
1418 INST(33U, Opcode::LoadPairPart).s64().Inputs(31U).Imm(0x0U);
1419 INST(32U, Opcode::LoadPairPart).s64().Inputs(31U).Imm(0x1U);
1420 INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({VirtualRegister::BRIDGE});
1421
1422 INST(30U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1423 INST(21U, Opcode::Add).s64().Inputs(32U, 33U);
1424 INST(22U, Opcode::Add).s64().Inputs(30U, 21U);
1425 INST(23U, Opcode::Return).s64().Inputs(22U);
1426 }
1427 }
1428 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1429 GraphChecker(GetGraph()).Check();
1430 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
1431 }
1432
TEST_F(MemoryCoalescingTest,OverSaveState)1433 TEST_F(MemoryCoalescingTest, OverSaveState)
1434 {
1435 // Coalescing is supported only for aarch64
1436 if (GetGraph()->GetArch() != Arch::AARCH64) {
1437 return;
1438 }
1439 GRAPH(GetGraph())
1440 {
1441 PARAMETER(0U, 0U).ref();
1442 BASIC_BLOCK(2U, -1L)
1443 {
1444 INST(1U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
1445 INST(11U, Opcode::SaveState).NoVregs();
1446 INST(2U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1447
1448 INST(3U, Opcode::StoreArrayI).s64().Inputs(0U, 2U).Imm(0x0U);
1449 INST(12U, Opcode::SaveState).NoVregs();
1450 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 1U).Imm(0x1U);
1451 INST(5U, Opcode::ReturnVoid).v0id();
1452 }
1453 }
1454 Graph *optGraph = CreateEmptyGraph();
1455 GRAPH(optGraph)
1456 {
1457 PARAMETER(0U, 0U).ref();
1458 BASIC_BLOCK(2U, -1L)
1459 {
1460 INST(6U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
1461 INST(7U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x0U);
1462 INST(8U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x1U);
1463 INST(27U, Opcode::SaveState).Inputs(0U).SrcVregs({VirtualRegister::BRIDGE});
1464
1465 INST(9U, Opcode::StoreArrayPairI).s64().Inputs(0U, 8U, 7U).Imm(0x0U);
1466 INST(28U, Opcode::SaveState).NoVregs();
1467 INST(5U, Opcode::ReturnVoid).v0id();
1468 }
1469 }
1470 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1471 GraphChecker(GetGraph()).Check();
1472 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
1473 }
1474
TEST_F(MemoryCoalescingTest,OnlySingleCoalescingOverSaveStateDeoptimize)1475 TEST_F(MemoryCoalescingTest, OnlySingleCoalescingOverSaveStateDeoptimize)
1476 {
1477 // Coalescing is supported only for aarch64
1478 if (GetGraph()->GetArch() != Arch::AARCH64) {
1479 return;
1480 }
1481 GRAPH(GetGraph())
1482 {
1483 PARAMETER(0U, 0U).ref();
1484 BASIC_BLOCK(2U, -1L)
1485 {
1486 INST(26U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
1487 INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
1488 INST(28U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1489
1490 INST(30U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1491 INST(21U, Opcode::Add).s64().Inputs(28U, 26U);
1492 INST(22U, Opcode::Add).s64().Inputs(30U, 21U);
1493 INST(23U, Opcode::Return).s64().Inputs(22U);
1494 }
1495 }
1496 Graph *optGraph = CreateEmptyGraph();
1497 GRAPH(optGraph)
1498 {
1499 PARAMETER(0U, 0U).ref();
1500 BASIC_BLOCK(2U, -1L)
1501 {
1502 INST(31U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
1503 INST(33U, Opcode::LoadPairPart).s64().Inputs(31U).Imm(0x0U);
1504 INST(32U, Opcode::LoadPairPart).s64().Inputs(31U).Imm(0x1U);
1505 INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
1506
1507 INST(30U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1508 INST(21U, Opcode::Add).s64().Inputs(32U, 33U);
1509 INST(22U, Opcode::Add).s64().Inputs(30U, 21U);
1510 INST(23U, Opcode::Return).s64().Inputs(22U);
1511 }
1512 }
1513 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1514 GraphChecker(GetGraph()).Check();
1515 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
1516 }
1517
TEST_F(MemoryCoalescingTest,OverSaveStateDeoptimize)1518 TEST_F(MemoryCoalescingTest, OverSaveStateDeoptimize)
1519 {
1520 // Coalescing is supported only for aarch64
1521 if (GetGraph()->GetArch() != Arch::AARCH64) {
1522 return;
1523 }
1524 GRAPH(GetGraph())
1525 {
1526 PARAMETER(0U, 0U).ref();
1527 BASIC_BLOCK(2U, -1L)
1528 {
1529 INST(1U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
1530 INST(11U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
1531 INST(2U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1532
1533 INST(3U, Opcode::StoreArrayI).s64().Inputs(0U, 2U).Imm(0x0U);
1534 INST(12U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
1535 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 1U).Imm(0x1U);
1536 INST(5U, Opcode::ReturnVoid).v0id();
1537 }
1538 }
1539 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1540 GraphChecker(GetGraph()).Check();
1541
1542 Graph *optGraph = CreateEmptyGraph();
1543 GRAPH(optGraph)
1544 {
1545 PARAMETER(0U, 0U).ref();
1546 BASIC_BLOCK(2U, -1L)
1547 {
1548 INST(6U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
1549 INST(7U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x0U);
1550 INST(8U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x1U);
1551 INST(27U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
1552
1553 INST(3U, Opcode::StoreArrayI).s64().Inputs(0U, 8U).Imm(0x0U);
1554 INST(12U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
1555 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 7U).Imm(0x1U);
1556 INST(5U, Opcode::ReturnVoid).v0id();
1557 }
1558 }
1559 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
1560 }
1561
TEST_F(MemoryCoalescingTest,OnlySingleCoalescingOverSaveStateWithCheckUser)1562 TEST_F(MemoryCoalescingTest, OnlySingleCoalescingOverSaveStateWithCheckUser)
1563 {
1564 // Coalescing is supported only for aarch64
1565 if (GetGraph()->GetArch() != Arch::AARCH64) {
1566 return;
1567 }
1568 GRAPH(GetGraph())
1569 {
1570 PARAMETER(0U, 0U).ref();
1571 BASIC_BLOCK(2U, -1L)
1572 {
1573 INST(26U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
1574 INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
1575 INST(28U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1576
1577 INST(30U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1578 INST(21U, Opcode::Add).s64().Inputs(28U, 26U);
1579 INST(22U, Opcode::Add).s64().Inputs(30U, 21U);
1580 INST(3U, Opcode::NullCheck).ref().Inputs(0U, 2U);
1581 INST(23U, Opcode::Return).s64().Inputs(22U);
1582 }
1583 }
1584 Graph *optGraph = CreateEmptyGraph();
1585 GRAPH(optGraph)
1586 {
1587 PARAMETER(0U, 0U).ref();
1588 BASIC_BLOCK(2U, -1L)
1589 {
1590 INST(31U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
1591 INST(33U, Opcode::LoadPairPart).s64().Inputs(31U).Imm(0x0U);
1592 INST(32U, Opcode::LoadPairPart).s64().Inputs(31U).Imm(0x1U);
1593 INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
1594
1595 INST(30U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1596 INST(21U, Opcode::Add).s64().Inputs(32U, 33U);
1597 INST(22U, Opcode::Add).s64().Inputs(30U, 21U);
1598 INST(3U, Opcode::NullCheck).ref().Inputs(0U, 2U);
1599 INST(23U, Opcode::Return).s64().Inputs(22U);
1600 }
1601 }
1602 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1603 GraphChecker(GetGraph()).Check();
1604 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
1605 }
1606
TEST_F(MemoryCoalescingTest,OverSaveStateWithCheckUser)1607 TEST_F(MemoryCoalescingTest, OverSaveStateWithCheckUser)
1608 {
1609 // Coalescing is supported only for aarch64
1610 if (GetGraph()->GetArch() != Arch::AARCH64) {
1611 return;
1612 }
1613 GRAPH(GetGraph())
1614 {
1615 PARAMETER(0U, 0U).ref();
1616 BASIC_BLOCK(2U, -1L)
1617 {
1618 INST(1U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
1619 INST(11U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
1620 INST(2U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1621
1622 INST(3U, Opcode::StoreArrayI).s64().Inputs(0U, 2U).Imm(0x0U);
1623 INST(12U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
1624 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 1U).Imm(0x1U);
1625 INST(13U, Opcode::NullCheck).ref().Inputs(0U, 11U);
1626 INST(14U, Opcode::NullCheck).ref().Inputs(0U, 12U);
1627 INST(5U, Opcode::ReturnVoid).v0id();
1628 }
1629 }
1630 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1631 GraphChecker(GetGraph()).Check();
1632
1633 Graph *optGraph = CreateEmptyGraph();
1634 GRAPH(optGraph)
1635 {
1636 PARAMETER(0U, 0U).ref();
1637 BASIC_BLOCK(2U, -1L)
1638 {
1639 INST(6U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
1640 INST(7U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x0U);
1641 INST(8U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x1U);
1642 INST(11U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
1643
1644 INST(3U, Opcode::StoreArrayI).s64().Inputs(0U, 8U).Imm(0x0U);
1645 INST(12U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
1646 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 7U).Imm(0x1U);
1647 INST(13U, Opcode::NullCheck).ref().Inputs(0U, 11U);
1648 INST(14U, Opcode::NullCheck).ref().Inputs(0U, 12U);
1649 INST(5U, Opcode::ReturnVoid).v0id();
1650 }
1651 }
1652 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
1653 }
1654
TEST_F(MemoryCoalescingTest,OverSaveStateWithDeoptimizeUser)1655 TEST_F(MemoryCoalescingTest, OverSaveStateWithDeoptimizeUser)
1656 {
1657 // Coalescing is supported only for aarch64
1658 if (GetGraph()->GetArch() != Arch::AARCH64) {
1659 return;
1660 }
1661 GRAPH(GetGraph())
1662 {
1663 PARAMETER(0U, 0U).ref();
1664 BASIC_BLOCK(2U, -1L)
1665 {
1666 INST(1U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x0U);
1667 INST(11U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
1668 INST(2U, Opcode::LoadArrayI).s64().Inputs(0U).Imm(0x1U);
1669
1670 INST(3U, Opcode::StoreArrayI).s64().Inputs(0U, 2U).Imm(0x0U);
1671 INST(12U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
1672 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 1U).Imm(0x1U);
1673 INST(13U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::NEGATIVE_CHECK).Inputs(11U);
1674 INST(14U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::NEGATIVE_CHECK).Inputs(12U);
1675 INST(5U, Opcode::ReturnVoid).v0id();
1676 }
1677 }
1678 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
1679 GraphChecker(GetGraph()).Check();
1680
1681 Graph *optGraph = CreateEmptyGraph();
1682 GRAPH(optGraph)
1683 {
1684 PARAMETER(0U, 0U).ref();
1685 BASIC_BLOCK(2U, -1L)
1686 {
1687 INST(6U, Opcode::LoadArrayPairI).s64().Inputs(0U).Imm(0x0U);
1688 INST(7U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x0U);
1689 INST(8U, Opcode::LoadPairPart).s64().Inputs(6U).Imm(0x1U);
1690 INST(11U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
1691
1692 INST(3U, Opcode::StoreArrayI).s64().Inputs(0U, 8U).Imm(0x0U);
1693 INST(12U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
1694 INST(4U, Opcode::StoreArrayI).s64().Inputs(0U, 7U).Imm(0x1U);
1695 INST(13U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::NEGATIVE_CHECK).Inputs(11U);
1696 INST(14U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::NEGATIVE_CHECK).Inputs(12U);
1697 INST(5U, Opcode::ReturnVoid).v0id();
1698 }
1699 }
1700 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), optGraph));
1701 }
1702 // NOLINTEND(readability-magic-numbers)
1703
1704 } // namespace ark::compiler
1705