• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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