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