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