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/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 panda::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
TEST_F(MemoryCoalescingTest,ImmidiateLoads)34 TEST_F(MemoryCoalescingTest, ImmidiateLoads)
35 {
36 // Coalescing is supported only for aarch64
37 if (GetGraph()->GetArch() != Arch::AARCH64) {
38 return;
39 }
40 GRAPH(GetGraph())
41 {
42 CONSTANT(0, 0x2a).s64();
43 BASIC_BLOCK(2, -1)
44 {
45 INST(44, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68);
46 INST(3, Opcode::NewArray).ref().Inputs(44, 0).TypeId(77);
47 INST(41, Opcode::SaveState).Inputs(3).SrcVregs({7});
48 INST(42, Opcode::NullCheck).ref().Inputs(3, 41);
49 INST(225, Opcode::LoadArrayI).s64().Inputs(42).Imm(0x0);
50 INST(227, Opcode::LoadArrayI).s64().Inputs(42).Imm(0x1);
51
52 INST(51, Opcode::Add).s64().Inputs(225, 227);
53 INST(229, Opcode::StoreArrayI).s64().Inputs(42, 51).Imm(0x0);
54 INST(230, Opcode::StoreArrayI).s64().Inputs(42, 51).Imm(0x1);
55 INST(40, Opcode::Return).s64().Inputs(51);
56 }
57 }
58 Graph *opt_graph = CreateEmptyGraph();
59 GRAPH(opt_graph)
60 {
61 CONSTANT(0, 0x2a).s64();
62 BASIC_BLOCK(2, -1)
63 {
64 INST(44, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68);
65 INST(3, Opcode::NewArray).ref().Inputs(44, 0).TypeId(77);
66 INST(41, Opcode::SaveState).Inputs(3).SrcVregs({7});
67 INST(42, Opcode::NullCheck).ref().Inputs(3, 41);
68 INST(231, Opcode::LoadArrayPairI).s64().Inputs(42).Imm(0x0);
69 INST(232, Opcode::LoadPairPart).s64().Inputs(231).Imm(0x0);
70 INST(233, Opcode::LoadPairPart).s64().Inputs(231).Imm(0x1);
71
72 INST(51, Opcode::Add).s64().Inputs(232, 233);
73 INST(234, Opcode::StoreArrayPairI).s64().Inputs(42, 51, 51).Imm(0x0);
74 INST(40, Opcode::Return).s64().Inputs(51);
75 }
76 }
77 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
78 GraphChecker(GetGraph()).Check();
79 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
80 }
81
TEST_F(MemoryCoalescingTest,LoopLoadCoalescing)82 TEST_F(MemoryCoalescingTest, LoopLoadCoalescing)
83 {
84 // Coalescing is supported only for aarch64
85 if (GetGraph()->GetArch() != Arch::AARCH64) {
86 return;
87 }
88 GRAPH(GetGraph())
89 {
90 PARAMETER(5, 0).ref();
91 CONSTANT(6, 0x0).s64();
92 BASIC_BLOCK(2, 3)
93 {
94 INST(35, Opcode::SaveState).Inputs(5).SrcVregs({1});
95 INST(36, Opcode::NullCheck).ref().Inputs(5, 35);
96 }
97 BASIC_BLOCK(3, 3, 7)
98 {
99 INST(9, Opcode::Phi).s32().Inputs({{2, 6}, {3, 64}});
100 INST(10, Opcode::Phi).s64().Inputs({{2, 6}, {3, 28}});
101 INST(19, Opcode::LoadArray).s64().Inputs(36, 9);
102 INST(63, Opcode::AddI).s32().Inputs(9).Imm(0x1);
103 INST(26, Opcode::LoadArray).s64().Inputs(36, 63);
104 INST(27, Opcode::Add).s64().Inputs(26, 19);
105 INST(28, Opcode::Add).s64().Inputs(27, 10);
106 INST(64, Opcode::AddI).s32().Inputs(9).Imm(0x2);
107 INST(31, Opcode::IfImm).SrcType(DataType::INT32).CC(CC_LT).Imm(0x4).Inputs(64);
108 }
109 BASIC_BLOCK(7, -1)
110 {
111 INST(33, Opcode::Return).s32().Inputs(28);
112 }
113 }
114 Graph *opt_graph = CreateEmptyGraph();
115 GRAPH(opt_graph)
116 {
117 PARAMETER(5, 0).ref();
118 CONSTANT(6, 0x0).s64();
119 BASIC_BLOCK(2, 3)
120 {
121 INST(35, Opcode::SaveState).Inputs(5).SrcVregs({1});
122 INST(36, Opcode::NullCheck).ref().Inputs(5, 35);
123 }
124 BASIC_BLOCK(3, 3, 7)
125 {
126 INST(9, Opcode::Phi).s32().Inputs({{2, 6}, {3, 64}});
127 INST(10, Opcode::Phi).s64().Inputs({{2, 6}, {3, 28}});
128 INST(65, Opcode::LoadArrayPair).s64().Inputs(36, 9);
129 INST(66, Opcode::LoadPairPart).s64().Inputs(65).Imm(0x0);
130 INST(67, Opcode::LoadPairPart).s64().Inputs(65).Imm(0x1);
131 INST(63, Opcode::AddI).s32().Inputs(9).Imm(0x1);
132 INST(27, Opcode::Add).s64().Inputs(67, 66);
133 INST(28, Opcode::Add).s64().Inputs(27, 10);
134 INST(64, Opcode::AddI).s32().Inputs(9).Imm(0x2);
135 INST(31, Opcode::IfImm).SrcType(DataType::INT32).CC(CC_LT).Imm(0x4).Inputs(64);
136 }
137 BASIC_BLOCK(7, -1)
138 {
139 INST(33, Opcode::Return).s32().Inputs(28);
140 }
141 }
142 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
143 GraphChecker(GetGraph()).Check();
144 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
145 }
146
TEST_F(MemoryCoalescingTest,LoopStoreCoalescing)147 TEST_F(MemoryCoalescingTest, LoopStoreCoalescing)
148 {
149 // Coalescing is supported only for aarch64
150 if (GetGraph()->GetArch() != Arch::AARCH64) {
151 return;
152 }
153 GRAPH(GetGraph())
154 {
155 PARAMETER(0, 0).ref();
156 CONSTANT(4, 0x0).s64();
157 CONSTANT(5, 0x1).s64();
158 BASIC_BLOCK(2, 3)
159 {
160 INST(3, Opcode::LenArray).s32().Inputs(0);
161 }
162 BASIC_BLOCK(3, 3, 4)
163 {
164 INST(6, Opcode::Phi).s32().Inputs({{2, 4}, {3, 34}});
165 INST(7, Opcode::Phi).s32().Inputs({{2, 5}, {3, 24}});
166 INST(8, Opcode::Phi).s32().Inputs({{2, 5}, {3, 25}});
167 INST(17, Opcode::StoreArray).s32().Inputs(0, 6, 7);
168 INST(33, Opcode::AddI).s32().Inputs(6).Imm(0x1);
169 INST(23, Opcode::StoreArray).s32().Inputs(0, 33, 8);
170 INST(24, Opcode::Add).s32().Inputs(7, 8);
171 INST(25, Opcode::Add).s32().Inputs(8, 24);
172 INST(34, Opcode::AddI).s32().Inputs(6).Imm(0x2);
173 INST(35, Opcode::If).SrcType(DataType::INT32).CC(CC_LT).Inputs(34, 3);
174 }
175 BASIC_BLOCK(4, -1)
176 {
177 INST(29, Opcode::ReturnVoid).v0id();
178 }
179 }
180 Graph *opt_graph = CreateEmptyGraph();
181 GRAPH(opt_graph)
182 {
183 PARAMETER(0, 0).ref();
184 CONSTANT(4, 0x0).s64();
185 CONSTANT(5, 0x1).s64();
186 BASIC_BLOCK(2, 3)
187 {
188 INST(3, Opcode::LenArray).s32().Inputs(0);
189 }
190 BASIC_BLOCK(3, 3, 4)
191 {
192 INST(6, Opcode::Phi).s32().Inputs({{2, 4}, {3, 34}});
193 INST(7, Opcode::Phi).s32().Inputs({{2, 5}, {3, 24}});
194 INST(8, Opcode::Phi).s32().Inputs({{2, 5}, {3, 25}});
195 INST(33, Opcode::AddI).s32().Inputs(6).Imm(0x1);
196 INST(36, Opcode::StoreArrayPair).s32().Inputs(0, 6, 7, 8);
197 INST(24, Opcode::Add).s32().Inputs(7, 8);
198 INST(25, Opcode::Add).s32().Inputs(8, 24);
199 INST(34, Opcode::AddI).s32().Inputs(6).Imm(0x2);
200 INST(35, Opcode::If).SrcType(DataType::INT32).CC(CC_LT).Inputs(34, 3);
201 }
202 BASIC_BLOCK(4, -1)
203 {
204 INST(29, Opcode::ReturnVoid).v0id();
205 }
206 }
207 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
208 GraphChecker(GetGraph()).Check();
209 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
210 }
211
TEST_F(MemoryCoalescingTest,AliasedAccess)212 TEST_F(MemoryCoalescingTest, AliasedAccess)
213 {
214 // Coalescing is supported only for aarch64
215 if (GetGraph()->GetArch() != Arch::AARCH64) {
216 return;
217 }
218 GRAPH(GetGraph())
219 {
220 PARAMETER(0, 0).ref();
221 BASIC_BLOCK(2, -1)
222 {
223 INST(26, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x0);
224 INST(28, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x1);
225 INST(21, Opcode::Add).s64().Inputs(28, 26);
226 INST(22, Opcode::Return).s64().Inputs(21);
227 }
228 }
229 Graph *opt_graph = CreateEmptyGraph();
230 GRAPH(opt_graph)
231 {
232 PARAMETER(0, 0).ref();
233 BASIC_BLOCK(2, -1)
234 {
235 INST(29, Opcode::LoadArrayPairI).s64().Inputs(0).Imm(0x0);
236 INST(30, Opcode::LoadPairPart).s64().Inputs(29).Imm(0x0);
237 INST(31, Opcode::LoadPairPart).s64().Inputs(29).Imm(0x1);
238 INST(21, Opcode::Add).s64().Inputs(31, 30);
239 INST(22, Opcode::Return).s64().Inputs(21);
240 }
241 }
242 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
243 GraphChecker(GetGraph()).Check();
244 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
245 }
246
TEST_F(MemoryCoalescingTest,OnlySingleCoalescing)247 TEST_F(MemoryCoalescingTest, OnlySingleCoalescing)
248 {
249 // Coalescing is supported only for aarch64
250 if (GetGraph()->GetArch() != Arch::AARCH64) {
251 return;
252 }
253 GRAPH(GetGraph())
254 {
255 PARAMETER(0, 0).ref();
256 BASIC_BLOCK(2, -1)
257 {
258 INST(26, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x0);
259 INST(28, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x1);
260
261 INST(30, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x1);
262 INST(21, Opcode::Add).s64().Inputs(28, 26);
263 INST(22, Opcode::Add).s64().Inputs(30, 21);
264 INST(23, Opcode::Return).s64().Inputs(22);
265 }
266 }
267 Graph *opt_graph = CreateEmptyGraph();
268 GRAPH(opt_graph)
269 {
270 PARAMETER(0, 0).ref();
271 BASIC_BLOCK(2, -1)
272 {
273 INST(31, Opcode::LoadArrayPairI).s64().Inputs(0).Imm(0x0);
274 INST(33, Opcode::LoadPairPart).s64().Inputs(31).Imm(0x0);
275 INST(32, Opcode::LoadPairPart).s64().Inputs(31).Imm(0x1);
276
277 INST(30, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x1);
278 INST(21, Opcode::Add).s64().Inputs(32, 33);
279 INST(22, Opcode::Add).s64().Inputs(30, 21);
280 INST(23, Opcode::Return).s64().Inputs(22);
281 }
282 }
283 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
284 GraphChecker(GetGraph()).Check();
285 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
286 }
287
TEST_F(MemoryCoalescingTest,PseudoParts)288 TEST_F(MemoryCoalescingTest, PseudoParts)
289 {
290 // Coalescing is supported only for aarch64
291 if (GetGraph()->GetArch() != Arch::AARCH64) {
292 return;
293 }
294 GRAPH(GetGraph())
295 {
296 PARAMETER(0, 0).ref();
297 BASIC_BLOCK(2, -1)
298 {
299 INST(1, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x0);
300 INST(2, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x1);
301
302 INST(3, Opcode::StoreArrayI).s64().Inputs(0, 2).Imm(0x0);
303 INST(4, Opcode::StoreArrayI).s64().Inputs(0, 1).Imm(0x1);
304 INST(5, Opcode::ReturnVoid).v0id();
305 }
306 }
307 Graph *opt_graph = CreateEmptyGraph();
308 GRAPH(opt_graph)
309 {
310 PARAMETER(0, 0).ref();
311 BASIC_BLOCK(2, -1)
312 {
313 INST(6, Opcode::LoadArrayPairI).s64().Inputs(0).Imm(0x0);
314 INST(7, Opcode::LoadPairPart).s64().Inputs(6).Imm(0x0);
315 INST(8, Opcode::LoadPairPart).s64().Inputs(6).Imm(0x1);
316
317 INST(9, Opcode::StoreArrayPairI).s64().Inputs(0, 8, 7).Imm(0x0);
318 INST(5, Opcode::ReturnVoid).v0id();
319 }
320 }
321 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
322 GetGraph()->RunPass<Scheduler>();
323 RegAlloc(GetGraph());
324 GraphChecker(GetGraph()).Check();
325 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
326 }
327
TEST_F(MemoryCoalescingTest,UnalignedStores)328 TEST_F(MemoryCoalescingTest, UnalignedStores)
329 {
330 // Coalescing is supported only for aarch64
331 if (GetGraph()->GetArch() != Arch::AARCH64) {
332 return;
333 }
334 GRAPH(GetGraph())
335 {
336 PARAMETER(0, 0).ref();
337 PARAMETER(1, 1).s64();
338 PARAMETER(2, 2).s64();
339 PARAMETER(3, 3).s64();
340 BASIC_BLOCK(2, -1)
341 {
342 INST(4, Opcode::AddI).s32().Inputs(1).Imm(0x4);
343 INST(5, Opcode::StoreArray).s32().Inputs(0, 4, 2);
344 INST(6, Opcode::AddI).s32().Inputs(1).Imm(0x5);
345 INST(7, Opcode::StoreArray).s32().Inputs(0, 6, 3);
346
347 INST(8, Opcode::StoreArray).s32().Inputs(0, 4, 3);
348 INST(9, Opcode::AddI).s32().Inputs(4).Imm(0x1);
349 INST(10, Opcode::StoreArray).s32().Inputs(0, 9, 2);
350 INST(11, Opcode::ReturnVoid).v0id();
351 }
352 }
353 Graph *opt_graph = CreateEmptyGraph();
354 GRAPH(opt_graph)
355 {
356 PARAMETER(0, 0).ref();
357 PARAMETER(1, 1).s64();
358 PARAMETER(2, 2).s64();
359 PARAMETER(3, 3).s64();
360 BASIC_BLOCK(2, -1)
361 {
362 INST(4, Opcode::AddI).s32().Inputs(1).Imm(0x4);
363 INST(6, Opcode::AddI).s32().Inputs(1).Imm(0x5);
364 INST(12, Opcode::StoreArrayPair).s32().Inputs(0, 4, 2, 3);
365
366 INST(9, Opcode::AddI).s32().Inputs(4).Imm(0x1);
367 INST(13, Opcode::StoreArrayPair).s32().Inputs(0, 4, 3, 2);
368 INST(11, Opcode::ReturnVoid).v0id();
369 }
370 }
371 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
372 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(true));
373 GraphChecker(GetGraph()).Check();
374 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
375
376 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
377 GraphChecker(GetGraph()).Check();
378 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
379 }
380
TEST_F(MemoryCoalescingTest,NoAlignmentTestI)381 TEST_F(MemoryCoalescingTest, NoAlignmentTestI)
382 {
383 // Coalescing is supported only for aarch64
384 if (GetGraph()->GetArch() != Arch::AARCH64) {
385 return;
386 }
387 GRAPH(GetGraph())
388 {
389 PARAMETER(0, 0).ref();
390 BASIC_BLOCK(2, -1)
391 {
392 INST(1, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x2);
393 INST(2, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x1);
394 INST(3, Opcode::Add).s64().Inputs(2, 1);
395 INST(4, Opcode::Return).s64().Inputs(3);
396 }
397 }
398 Graph *opt_graph = CreateEmptyGraph();
399 GRAPH(opt_graph)
400 {
401 PARAMETER(0, 0).ref();
402 BASIC_BLOCK(2, -1)
403 {
404 INST(5, Opcode::LoadArrayPairI).s64().Inputs(0).Imm(0x1);
405 INST(6, Opcode::LoadPairPart).s64().Inputs(5).Imm(0x0);
406 INST(7, Opcode::LoadPairPart).s64().Inputs(5).Imm(0x1);
407 INST(3, Opcode::Add).s64().Inputs(6, 7);
408 INST(4, Opcode::Return).s64().Inputs(3);
409 }
410 }
411 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
412 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(true));
413 GraphChecker(GetGraph()).Check();
414 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
415
416 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
417 GraphChecker(GetGraph()).Check();
418 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
419 }
420
TEST_F(MemoryCoalescingTest,StoresRoundedByLoads)421 TEST_F(MemoryCoalescingTest, StoresRoundedByLoads)
422 {
423 // Coalescing is supported only for aarch64
424 if (GetGraph()->GetArch() != Arch::AARCH64) {
425 return;
426 }
427 GRAPH(GetGraph())
428 {
429 PARAMETER(0, 0).ref();
430 PARAMETER(1, 1).s64();
431 PARAMETER(2, 2).s64();
432 BASIC_BLOCK(2, -1)
433 {
434 INST(3, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x2);
435 INST(4, Opcode::StoreArrayI).s64().Inputs(0, 1).Imm(0x2);
436 INST(5, Opcode::StoreArrayI).s64().Inputs(0, 2).Imm(0x3);
437 INST(6, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x3);
438 INST(7, Opcode::Add).s64().Inputs(3, 6);
439 INST(8, Opcode::Return).s64().Inputs(7);
440 }
441 }
442 Graph *opt_graph = CreateEmptyGraph();
443 GRAPH(opt_graph)
444 {
445 PARAMETER(0, 0).ref();
446 PARAMETER(1, 1).s64();
447 PARAMETER(2, 2).s64();
448 BASIC_BLOCK(2, -1)
449 {
450 INST(3, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x2);
451 INST(9, Opcode::StoreArrayPairI).s64().Inputs(0, 1, 2).Imm(0x2);
452 INST(6, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x3);
453 INST(7, Opcode::Add).s64().Inputs(3, 6);
454 INST(8, Opcode::Return).s64().Inputs(7);
455 }
456 }
457 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
458 GraphChecker(GetGraph()).Check();
459 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
460 }
461
TEST_F(MemoryCoalescingTest,UnalignedInLoop)462 TEST_F(MemoryCoalescingTest, UnalignedInLoop)
463 {
464 // Coalescing is supported only for aarch64
465 if (GetGraph()->GetArch() != Arch::AARCH64) {
466 return;
467 }
468 GRAPH(GetGraph())
469 {
470 PARAMETER(0, 0).s32();
471 PARAMETER(1, 1).s32();
472 CONSTANT(3, 0xa).s64();
473 BASIC_BLOCK(2, 3)
474 {
475 INST(44, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68);
476 INST(6, Opcode::NewArray).ref().Inputs(44, 3).TypeId(77);
477 }
478 BASIC_BLOCK(3, 3, 4)
479 {
480 INST(7, Opcode::Phi).s32().Inputs({{2, 0}, {3, 33}});
481 INST(19, Opcode::StoreArray).s32().Inputs(6, 7, 7);
482 INST(33, Opcode::AddI).s32().Inputs(7).Imm(0x1);
483 INST(25, Opcode::StoreArray).s32().Inputs(6, 33, 7);
484 INST(34, Opcode::If).SrcType(DataType::INT32).CC(CC_GT).Inputs(1, 33);
485 }
486 BASIC_BLOCK(4, -1)
487 {
488 INST(29, Opcode::Return).s32().Inputs(33);
489 }
490 }
491 Graph *opt_graph = CreateEmptyGraph();
492 GRAPH(opt_graph)
493 {
494 PARAMETER(0, 0).s32();
495 PARAMETER(1, 1).s32();
496 CONSTANT(3, 0xa).s64();
497 BASIC_BLOCK(2, 3)
498 {
499 INST(44, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68);
500 INST(6, Opcode::NewArray).ref().Inputs(44, 3).TypeId(77);
501 }
502 BASIC_BLOCK(3, 3, 4)
503 {
504 INST(7, Opcode::Phi).s32().Inputs({{2, 0}, {3, 33}});
505 INST(33, Opcode::AddI).s32().Inputs(7).Imm(0x1);
506 INST(35, Opcode::StoreArrayPair).s32().Inputs(6, 7, 7, 7);
507 INST(34, Opcode::If).SrcType(DataType::INT32).CC(CC_GT).Inputs(1, 33);
508 }
509 BASIC_BLOCK(4, -1)
510 {
511 INST(29, Opcode::Return).s32().Inputs(33);
512 }
513 }
514 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
515 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(true));
516 GraphChecker(GetGraph()).Check();
517 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
518
519 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
520 GraphChecker(GetGraph()).Check();
521 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
522 }
523
TEST_F(MemoryCoalescingTest,IndexInference)524 TEST_F(MemoryCoalescingTest, IndexInference)
525 {
526 // Coalescing is supported only for aarch64
527 if (GetGraph()->GetArch() != Arch::AARCH64) {
528 return;
529 }
530 GRAPH(GetGraph())
531 {
532 PARAMETER(0, 0).ref();
533 PARAMETER(1, 1).s64();
534 BASIC_BLOCK(2, -1)
535 {
536 INST(6, Opcode::AddI).s32().Inputs(1).Imm(0x1);
537 INST(7, Opcode::LoadArray).s32().Inputs(0, 1);
538 INST(8, Opcode::LoadArray).s32().Inputs(0, 6);
539 INST(9, Opcode::StoreArray).s32().Inputs(0, 1, 7);
540 INST(10, Opcode::StoreArray).s32().Inputs(0, 6, 8);
541 INST(11, Opcode::ReturnVoid).v0id();
542 }
543 }
544 Graph *opt_graph = CreateEmptyGraph();
545 GRAPH(opt_graph)
546 {
547 PARAMETER(0, 0).ref();
548 PARAMETER(1, 1).s64();
549 BASIC_BLOCK(2, -1)
550 {
551 INST(6, Opcode::AddI).s32().Inputs(1).Imm(0x1);
552 INST(12, Opcode::LoadArrayPair).s32().Inputs(0, 1);
553 INST(14, Opcode::LoadPairPart).s32().Inputs(12).Imm(0x0);
554 INST(13, Opcode::LoadPairPart).s32().Inputs(12).Imm(0x1);
555 INST(15, Opcode::StoreArrayPair).s32().Inputs(0, 1, 14, 13);
556 INST(11, Opcode::ReturnVoid).v0id();
557 }
558 }
559 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
560 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(true));
561 GraphChecker(GetGraph()).Check();
562 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
563
564 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
565 GraphChecker(GetGraph()).Check();
566 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
567 }
568
TEST_F(MemoryCoalescingTest,SimplePlaceFinding)569 TEST_F(MemoryCoalescingTest, SimplePlaceFinding)
570 {
571 // Coalescing is supported only for aarch64
572 if (GetGraph()->GetArch() != Arch::AARCH64) {
573 return;
574 }
575 GRAPH(GetGraph())
576 {
577 PARAMETER(0, 0).ref();
578 PARAMETER(1, 1).s64();
579 BASIC_BLOCK(2, -1)
580 {
581 INST(7, Opcode::LoadArray).s32().Inputs(0, 1);
582 INST(6, Opcode::SubI).s32().Inputs(1).Imm(1);
583 INST(8, Opcode::LoadArray).s32().Inputs(0, 6);
584 INST(9, Opcode::Add).s32().Inputs(7, 8);
585 INST(11, Opcode::Return).s32().Inputs(9);
586 }
587 }
588 Graph *opt_graph = CreateEmptyGraph();
589 GRAPH(opt_graph)
590 {
591 PARAMETER(0, 0).ref();
592 PARAMETER(1, 1).s64();
593 BASIC_BLOCK(2, -1)
594 {
595 INST(6, Opcode::SubI).s32().Inputs(1).Imm(1);
596 INST(12, Opcode::LoadArrayPair).s32().Inputs(0, 6);
597 INST(14, Opcode::LoadPairPart).s32().Inputs(12).Imm(0x0);
598 INST(13, Opcode::LoadPairPart).s32().Inputs(12).Imm(0x1);
599 INST(9, Opcode::Add).s32().Inputs(13, 14);
600 INST(11, Opcode::Return).s32().Inputs(9);
601 }
602 }
603 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
604 GraphChecker(GetGraph()).Check();
605 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
606 }
607
TEST_F(MemoryCoalescingTest,ObjectAccessesCoalescing)608 TEST_F(MemoryCoalescingTest, ObjectAccessesCoalescing)
609 {
610 // Coalescing is supported only for aarch64
611 if (GetGraph()->GetArch() != Arch::AARCH64) {
612 return;
613 }
614 GRAPH(GetGraph())
615 {
616 PARAMETER(0, 0).ref();
617 CONSTANT(1, 0x2).s64();
618 BASIC_BLOCK(2, -1)
619 {
620 INST(50, Opcode::SaveState).Inputs(0).SrcVregs({0});
621 INST(44, Opcode::LoadAndInitClass).ref().Inputs(50).TypeId(68);
622 INST(4, Opcode::NewArray).ref().Inputs(44, 1, 50).TypeId(88);
623 INST(38, Opcode::LoadArrayI).ref().Inputs(0).Imm(0x0);
624 INST(40, Opcode::LoadArrayI).ref().Inputs(0).Imm(0x1);
625 INST(41, Opcode::StoreArrayI).ref().Inputs(4, 38).Imm(0x0);
626 INST(42, Opcode::StoreArrayI).ref().Inputs(4, 40).Imm(0x1);
627 INST(27, Opcode::ReturnVoid).v0id();
628 }
629 }
630 Graph *opt_graph = CreateEmptyGraph();
631 GRAPH(opt_graph)
632 {
633 PARAMETER(0, 0).ref();
634 CONSTANT(1, 0x2).s64();
635 BASIC_BLOCK(2, -1)
636 {
637 INST(50, Opcode::SaveState).Inputs(0).SrcVregs({0});
638 INST(444, Opcode::LoadAndInitClass).ref().Inputs(50).TypeId(68);
639 INST(4, Opcode::NewArray).ref().Inputs(444, 1, 50).TypeId(88);
640 INST(43, Opcode::LoadArrayPairI).ref().Inputs(0).Imm(0x0);
641 INST(45, Opcode::LoadPairPart).ref().Inputs(43).Imm(0x0);
642 INST(44, Opcode::LoadPairPart).ref().Inputs(43).Imm(0x1);
643 INST(46, Opcode::StoreArrayPairI).ref().Inputs(4, 45, 44).Imm(0x0);
644 INST(27, Opcode::ReturnVoid).v0id();
645 }
646 }
647 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
648 options.SetCompilerMemoryCoalescingObjects(false);
649 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(true));
650 GraphChecker(GetGraph()).Check();
651 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
652
653 options.SetCompilerMemoryCoalescingObjects(true);
654 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(true));
655 GraphChecker(GetGraph()).Check();
656 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
657 }
658
TEST_F(MemoryCoalescingTest,AllowedVolatileReordering)659 TEST_F(MemoryCoalescingTest, AllowedVolatileReordering)
660 {
661 // Coalescing is supported only for aarch64
662 if (GetGraph()->GetArch() != Arch::AARCH64) {
663 return;
664 }
665 GRAPH(GetGraph())
666 {
667 CONSTANT(0, 0x2a).s64();
668 BASIC_BLOCK(2, -1)
669 {
670 INST(4, Opcode::SaveState).SrcVregs({});
671 INST(5, Opcode::LoadAndInitClass).ref().Inputs(4).TypeId(0);
672
673 INST(3, Opcode::NewArray).ref().Inputs(5, 0).TypeId(77);
674 // Can reorder Volatile Store (v226) and Normal Load (v227)
675 INST(225, Opcode::LoadArrayI).s64().Inputs(3).Imm(0x0);
676 INST(226, Opcode::StoreStatic).s64().Volatile().Inputs(5, 225).TypeId(103);
677 INST(227, Opcode::LoadArrayI).s64().Inputs(3).Imm(0x1);
678
679 INST(51, Opcode::Add).s64().Inputs(225, 227);
680 // Can reorder Normal Store (v229) and Volatile Load (v230)
681 INST(229, Opcode::StoreArrayI).s64().Inputs(3, 51).Imm(0x0);
682 INST(230, Opcode::LoadStatic).s64().Inputs(5).Volatile().TypeId(107);
683 INST(231, Opcode::StoreArrayI).s64().Inputs(3, 230).Imm(0x1);
684 INST(40, Opcode::Return).s64().Inputs(51);
685 }
686 }
687 Graph *opt_graph = CreateEmptyGraph();
688 GRAPH(opt_graph)
689 {
690 CONSTANT(0, 0x2a).s64();
691 BASIC_BLOCK(2, -1)
692 {
693 INST(4, Opcode::SaveState).SrcVregs({});
694 INST(5, Opcode::LoadAndInitClass).ref().Inputs(4).TypeId(0);
695
696 INST(3, Opcode::NewArray).ref().Inputs(5, 0).TypeId(77);
697 INST(232, Opcode::LoadArrayPairI).s64().Inputs(3).Imm(0x0);
698 INST(234, Opcode::LoadPairPart).s64().Inputs(232).Imm(0x0);
699 INST(233, Opcode::LoadPairPart).s64().Inputs(232).Imm(0x1);
700 INST(226, Opcode::StoreStatic).s64().Volatile().Inputs(5, 234).TypeId(103);
701
702 INST(51, Opcode::Add).s64().Inputs(234, 233);
703 INST(230, Opcode::LoadStatic).s64().Inputs(5).Volatile().TypeId(107);
704 INST(235, Opcode::StoreArrayPairI).s64().Inputs(3, 51, 230).Imm(0x0);
705 INST(40, Opcode::Return).s64().Inputs(51);
706 }
707 }
708 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
709 GraphChecker(GetGraph()).Check();
710 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
711 }
712
TEST_F(MemoryCoalescingTest,AllowedVolatileReordering2)713 TEST_F(MemoryCoalescingTest, AllowedVolatileReordering2)
714 {
715 // Coalescing is supported only for aarch64
716 if (GetGraph()->GetArch() != Arch::AARCH64) {
717 return;
718 }
719 GRAPH(GetGraph())
720 {
721 CONSTANT(0, 0x2a).s64();
722 BASIC_BLOCK(2, -1)
723 {
724 INST(4, Opcode::SaveState).SrcVregs({});
725 INST(5, Opcode::LoadAndInitClass).ref().Inputs(4).TypeId(0);
726
727 INST(3, Opcode::NewArray).ref().Inputs(5, 0).TypeId(77);
728 // We can reorder v225 and v226 but not v226 and v227
729 INST(225, Opcode::LoadArrayI).s64().Inputs(3).Imm(0x0);
730 INST(226, Opcode::LoadStatic).s64().Inputs(5).Volatile().TypeId(103);
731 INST(227, Opcode::LoadArrayI).s64().Inputs(3).Imm(0x1);
732
733 INST(51, Opcode::Add).s64().Inputs(225, 227);
734 // We can reorder v230 and v231 but not v229 and v230
735 INST(229, Opcode::StoreArrayI).s64().Inputs(3, 51).Imm(0x0);
736 INST(230, Opcode::StoreStatic).s64().Inputs(5).Volatile().Inputs(226).TypeId(105);
737 INST(231, Opcode::StoreArrayI).s64().Inputs(3, 51).Imm(0x1);
738 INST(40, Opcode::Return).s64().Inputs(51);
739 }
740 }
741 Graph *opt_graph = CreateEmptyGraph();
742 GRAPH(opt_graph)
743 {
744 CONSTANT(0, 0x2a).s64();
745 BASIC_BLOCK(2, -1)
746 {
747 INST(4, Opcode::SaveState).SrcVregs({});
748 INST(5, Opcode::LoadAndInitClass).ref().Inputs(4).TypeId(0);
749
750 INST(3, Opcode::NewArray).ref().Inputs(5, 0).TypeId(77);
751 INST(226, Opcode::LoadStatic).s64().Inputs(5).Volatile().TypeId(103);
752 INST(235, Opcode::LoadArrayPairI).s64().Inputs(3).Imm(0x0);
753 INST(237, Opcode::LoadPairPart).s64().Inputs(235).Imm(0x0);
754 INST(236, Opcode::LoadPairPart).s64().Inputs(235).Imm(0x1);
755
756 INST(51, Opcode::Add).s64().Inputs(237, 236);
757 INST(238, Opcode::StoreArrayPairI).s64().Inputs(3, 51, 51).Imm(0x0);
758 INST(230, Opcode::StoreStatic).s64().Inputs(5).Volatile().Inputs(226).TypeId(105);
759 INST(40, Opcode::Return).s64().Inputs(51);
760 }
761 }
762 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
763 GraphChecker(GetGraph()).Check();
764 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
765 }
766
TEST_F(MemoryCoalescingTest,UnrolledLoop)767 TEST_F(MemoryCoalescingTest, UnrolledLoop)
768 {
769 // Coalescing is supported only for aarch64
770 if (GetGraph()->GetArch() != Arch::AARCH64) {
771 return;
772 }
773 GRAPH(GetGraph())
774 {
775 PARAMETER(0, 0).s64();
776 PARAMETER(1, 1).ref();
777 CONSTANT(3, 0x2a).s64();
778 CONSTANT(4, 0x0).s64();
779 BASIC_BLOCK(2, 3, 4)
780 {
781 INST(50, Opcode::SaveState).Inputs(1).SrcVregs({0});
782 INST(44, Opcode::LoadAndInitClass).ref().Inputs(50).TypeId(68);
783 INST(2, Opcode::NewArray).ref().Inputs(44, 3, 50).TypeId(77);
784 INST(10, Opcode::IfImm).SrcType(DataType::INT64).CC(CC_LE).Imm(0x0).Inputs(0);
785 }
786 BASIC_BLOCK(3, 3, 4)
787 {
788 INST(11, Opcode::Phi).s32().Inputs({{2, 4}, {3, 17}});
789 INST(12, Opcode::LoadArray).s32().Inputs(1, 11);
790 INST(13, Opcode::StoreArray).s32().Inputs(2, 11, 12);
791 INST(14, Opcode::AddI).s32().Inputs(11).Imm(1);
792
793 INST(15, Opcode::LoadArray).s32().Inputs(1, 14);
794 INST(16, Opcode::StoreArray).s32().Inputs(2, 14, 15);
795 INST(17, Opcode::AddI).s32().Inputs(11).Imm(2);
796
797 INST(30, Opcode::If).SrcType(DataType::INT32).CC(CC_GE).Inputs(17, 3);
798 }
799 BASIC_BLOCK(4, -1)
800 {
801 INST(40, Opcode::ReturnVoid);
802 }
803 }
804 Graph *opt_graph = CreateEmptyGraph();
805 GRAPH(opt_graph)
806 {
807 PARAMETER(0, 0).s64();
808 PARAMETER(1, 1).ref();
809 CONSTANT(3, 0x2a).s64();
810 CONSTANT(4, 0x0).s64();
811 BASIC_BLOCK(2, 3, 4)
812 {
813 INST(50, Opcode::SaveState).Inputs(1).SrcVregs({0});
814 INST(444, Opcode::LoadAndInitClass).ref().Inputs(50).TypeId(68);
815 INST(2, Opcode::NewArray).ref().Inputs(444, 3, 50).TypeId(77);
816 INST(10, Opcode::IfImm).SrcType(DataType::INT64).CC(CC_LE).Imm(0x0).Inputs(0);
817 }
818 BASIC_BLOCK(3, 3, 4)
819 {
820 INST(11, Opcode::Phi).s32().Inputs({{2, 4}, {3, 17}});
821 INST(44, Opcode::LoadArrayPair).s32().Inputs(1, 11);
822 INST(46, Opcode::LoadPairPart).s32().Inputs(44).Imm(0x0);
823 INST(45, Opcode::LoadPairPart).s32().Inputs(44).Imm(0x1);
824 INST(14, Opcode::AddI).s32().Inputs(11).Imm(1);
825
826 INST(47, Opcode::StoreArrayPair).s32().Inputs(2, 11, 46, 45);
827 INST(17, Opcode::AddI).s32().Inputs(11).Imm(2);
828
829 INST(30, Opcode::If).SrcType(DataType::INT32).CC(CC_GE).Inputs(17, 3);
830 }
831 BASIC_BLOCK(4, -1)
832 {
833 INST(40, Opcode::ReturnVoid);
834 }
835 }
836 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>());
837 GraphChecker(GetGraph()).Check();
838 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), opt_graph));
839 }
840
TEST_F(MemoryCoalescingTest,CoalescingOverSaveState)841 TEST_F(MemoryCoalescingTest, CoalescingOverSaveState)
842 {
843 // Coalescing is supported only for aarch64
844 if (GetGraph()->GetArch() != Arch::AARCH64) {
845 return;
846 }
847 GRAPH(GetGraph())
848 {
849 PARAMETER(0, 0).ref();
850 BASIC_BLOCK(2, -1)
851 {
852 INST(1, Opcode::SaveState).Inputs(0).SrcVregs({6});
853 INST(2, Opcode::NullCheck).ref().Inputs(0, 1);
854
855 INST(41, Opcode::SaveState).Inputs(0).SrcVregs({6});
856 INST(43, Opcode::LenArray).s32().Inputs(2);
857 INST(241, Opcode::BoundsCheckI).s32().Inputs(43, 41).Imm(0x0);
858 INST(242, Opcode::LoadArrayI).s64().Inputs(2).Imm(0x0);
859
860 INST(47, Opcode::SaveState).Inputs(242, 0).SrcVregs({3, 6});
861 INST(49, Opcode::LenArray).s32().Inputs(2);
862 INST(244, Opcode::BoundsCheckI).s32().Inputs(49, 47).Imm(0x1);
863 INST(245, Opcode::LoadArrayI).s64().Inputs(2).Imm(0x1);
864
865 INST(53, Opcode::Add).s64().Inputs(242, 245);
866 INST(40, Opcode::Return).s64().Inputs(53);
867 }
868 }
869 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
870 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
871 GraphChecker(GetGraph()).Check();
872 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
873 }
874
TEST_F(MemoryCoalescingTest,AlignmentTest)875 TEST_F(MemoryCoalescingTest, AlignmentTest)
876 {
877 // Coalescing is supported only for aarch64
878 if (GetGraph()->GetArch() != Arch::AARCH64) {
879 return;
880 }
881 GRAPH(GetGraph())
882 {
883 PARAMETER(0, 0).ref();
884 BASIC_BLOCK(2, -1)
885 {
886 INST(26, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x2);
887 INST(28, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x1);
888 INST(21, Opcode::Add).s64().Inputs(28, 26);
889 INST(22, Opcode::Return).s64().Inputs(21);
890 }
891 }
892 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
893 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
894 GraphChecker(GetGraph()).Check();
895 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
896 }
897
TEST_F(MemoryCoalescingTest,AliasedStore)898 TEST_F(MemoryCoalescingTest, AliasedStore)
899 {
900 // Coalescing is supported only for aarch64
901 if (GetGraph()->GetArch() != Arch::AARCH64) {
902 return;
903 }
904 GRAPH(GetGraph())
905 {
906 PARAMETER(0, 0).ref();
907 PARAMETER(1, 1).s64();
908 PARAMETER(2, 2).s64();
909 BASIC_BLOCK(2, -1)
910 {
911 INST(26, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x0);
912 INST(13, Opcode::StoreArray).s64().Inputs(0, 1, 2);
913 INST(28, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x5);
914 INST(29, Opcode::LoadArrayI).s64().Inputs(0).Imm(0x1);
915 INST(21, Opcode::Add).s64().Inputs(28, 26);
916 INST(24, Opcode::Add).s64().Inputs(21, 29);
917 INST(22, Opcode::Return).s64().Inputs(24);
918 }
919 }
920 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
921 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
922 GraphChecker(GetGraph()).Check();
923 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
924 }
925
TEST_F(MemoryCoalescingTest,TypeCheck)926 TEST_F(MemoryCoalescingTest, TypeCheck)
927 {
928 GRAPH(GetGraph())
929 {
930 PARAMETER(0, 0).ref();
931 PARAMETER(1, 1).s64();
932 BASIC_BLOCK(2, -1)
933 {
934 INST(6, Opcode::AddI).s32().Inputs(1).Imm(0x1);
935 INST(7, Opcode::LoadArray).s8().Inputs(0, 1);
936 INST(8, Opcode::LoadArray).s8().Inputs(0, 6);
937 INST(9, Opcode::LoadArrayI).s16().Inputs(0).Imm(0x4);
938 INST(10, Opcode::LoadArrayI).s16().Inputs(0).Imm(0x5);
939 INST(11, Opcode::StoreArray).s16().Inputs(0, 1, 9);
940 INST(12, Opcode::StoreArray).s16().Inputs(0, 6, 10);
941 INST(13, Opcode::StoreArrayI).s8().Inputs(0, 7).Imm(0x4);
942 INST(14, Opcode::StoreArrayI).s8().Inputs(0, 8).Imm(0x5);
943 INST(15, Opcode::ReturnVoid).v0id();
944 }
945 }
946 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
947 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
948 GraphChecker(GetGraph()).Check();
949 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
950 }
951
TEST_F(MemoryCoalescingTest,ProhibitedVolatileReordering)952 TEST_F(MemoryCoalescingTest, ProhibitedVolatileReordering)
953 {
954 // Coalescing is supported only for aarch64
955 if (GetGraph()->GetArch() != Arch::AARCH64) {
956 return;
957 }
958 GRAPH(GetGraph())
959 {
960 CONSTANT(0, 0x2a).s64();
961 BASIC_BLOCK(2, -1)
962 {
963 INST(4, Opcode::SaveState).SrcVregs({});
964 INST(5, Opcode::LoadAndInitClass).ref().Inputs(4).TypeId(0);
965
966 INST(3, Opcode::NewArray).ref().Inputs(5, 0).TypeId(77);
967 INST(225, Opcode::LoadArrayI).s64().Inputs(3).Imm(0x0);
968 // v50 is needed to prevent reordering v225 with v226
969 INST(50, Opcode::Add).s64().Inputs(225, 225);
970 INST(226, Opcode::LoadStatic).s64().Inputs(5).Volatile().TypeId(103);
971 INST(227, Opcode::LoadArrayI).s64().Inputs(3).Imm(0x1);
972
973 INST(51, Opcode::Add).s64().Inputs(50, 227);
974 INST(229, Opcode::StoreArrayI).s64().Inputs(3, 51).Imm(0x0);
975 INST(230, Opcode::StoreStatic).s64().Inputs(5).Volatile().Inputs(226).TypeId(105);
976 // v51 is needed to prevent reordering v231 and v230
977 INST(52, Opcode::Add).s64().Inputs(50, 51);
978 INST(231, Opcode::StoreArrayI).s64().Inputs(3, 52).Imm(0x1);
979 INST(40, Opcode::Return).s64().Inputs(51);
980 }
981 }
982 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
983 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
984 GraphChecker(GetGraph()).Check();
985 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
986 }
987
TEST_F(MemoryCoalescingTest,LoweringDominance)988 TEST_F(MemoryCoalescingTest, LoweringDominance)
989 {
990 // Coalescing is supported only for aarch64
991 if (GetGraph()->GetArch() != Arch::AARCH64) {
992 return;
993 }
994 GRAPH(GetGraph())
995 {
996 PARAMETER(0, 0).ref();
997 PARAMETER(1, 1).s64();
998 BASIC_BLOCK(2, -1)
999 {
1000 INST(8, Opcode::SubI).s32().Inputs(1).Imm(1);
1001
1002 INST(9, Opcode::LoadArray).s32().Inputs(0, 1);
1003 INST(10, Opcode::ShlI).s32().Inputs(9).Imm(24);
1004 INST(16, Opcode::StoreArray).s32().Inputs(0, 8, 10);
1005 INST(11, Opcode::AShrI).s32().Inputs(9).Imm(28);
1006
1007 INST(12, Opcode::AddI).s64().Inputs(1).Imm(1);
1008 INST(13, Opcode::LoadArray).s32().Inputs(0, 12);
1009
1010 INST(14, Opcode::Add).s32().Inputs(10, 11);
1011 INST(15, Opcode::Return).s32().Inputs(14);
1012 }
1013 }
1014 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1015 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>(false));
1016 GraphChecker(GetGraph()).Check();
1017 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
1018 }
1019
TEST_F(MemoryCoalescingTest,LoweringDominance2)1020 TEST_F(MemoryCoalescingTest, LoweringDominance2)
1021 {
1022 // Coalescing is supported only for aarch64
1023 if (GetGraph()->GetArch() != Arch::AARCH64) {
1024 return;
1025 }
1026 GRAPH(GetGraph())
1027 {
1028 PARAMETER(0, 0).ref();
1029 PARAMETER(1, 1).ref();
1030 PARAMETER(2, 2).ref();
1031 PARAMETER(3, 3).s64();
1032 BASIC_BLOCK(2, -1)
1033 {
1034 INST(8, Opcode::SubI).s32().Inputs(3).Imm(1);
1035
1036 INST(9, Opcode::LoadArrayI).s32().Inputs(0).Imm(0x0);
1037 INST(10, Opcode::StoreArray).s32().Inputs(1, 8, 9);
1038
1039 INST(11, Opcode::LoadArrayI).s32().Inputs(0).Imm(0x1);
1040 INST(12, Opcode::StoreArray).s32().Inputs(2, 8, 11);
1041
1042 INST(15, Opcode::Return).s32().Inputs(3);
1043 }
1044 }
1045 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1046 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
1047 GraphChecker(GetGraph()).Check();
1048 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
1049 }
1050
TEST_F(MemoryCoalescingTest,CoalescingLoadsOverSaveState)1051 TEST_F(MemoryCoalescingTest, CoalescingLoadsOverSaveState)
1052 {
1053 // Coalescing is supported only for aarch64
1054 if (GetGraph()->GetArch() != Arch::AARCH64) {
1055 return;
1056 }
1057 GRAPH(GetGraph())
1058 {
1059 PARAMETER(0, 0).ref();
1060 PARAMETER(1, 1).s64();
1061 BASIC_BLOCK(2, -1)
1062 {
1063 INST(9, Opcode::LoadArray).ref().Inputs(0, 1);
1064 INST(10, Opcode::SaveState).SrcVregs({9});
1065 INST(11, Opcode::AddI).s64().Inputs(1).Imm(1);
1066 INST(12, Opcode::LoadArray).ref().Inputs(0, 11);
1067 INST(13, Opcode::SaveState).SrcVregs({9, 12});
1068 INST(15, Opcode::Return).s32().Inputs(1);
1069 }
1070 }
1071 auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1072 ASSERT_FALSE(GetGraph()->RunPass<MemoryCoalescing>());
1073 GraphChecker(GetGraph()).Check();
1074 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
1075 }
1076
TEST_F(MemoryCoalescingTest,CoalescingPhiAsUser)1077 TEST_F(MemoryCoalescingTest, CoalescingPhiAsUser)
1078 {
1079 // Coalescing is supported only for aarch64
1080 if (GetGraph()->GetArch() != Arch::AARCH64) {
1081 return;
1082 }
1083 GRAPH(GetGraph())
1084 {
1085 PARAMETER(0, 0).ref();
1086 PARAMETER(1, 1).ref();
1087 PARAMETER(2, 2).s32();
1088 PARAMETER(3, 3).s32();
1089 BASIC_BLOCK(2, 3, 2)
1090 {
1091 INST(9, Opcode::Phi).s32().Inputs({{0, 3}, {2, 10}});
1092 INST(10, Opcode::LoadArray).s32().Inputs(0, 9);
1093 INST(11, Opcode::AddI).s32().Inputs(9).Imm(1);
1094 INST(12, Opcode::LoadArray).s32().Inputs(0, 11);
1095 INST(18, Opcode::IfImm).SrcType(DataType::INT32).CC(CC_EQ).Imm(0).Inputs(12);
1096 }
1097 BASIC_BLOCK(3, -1)
1098 {
1099 INST(20, Opcode::Return).s32().Inputs(2);
1100 }
1101 }
1102 ASSERT_TRUE(GetGraph()->RunPass<MemoryCoalescing>(false));
1103 GraphChecker(GetGraph()).Check();
1104 }
1105 } // namespace panda::compiler
1106