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