• 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 "macros.h"
17 #include "unit_test.h"
18 #include "optimizer/ir/graph_cloner.h"
19 #include "optimizer/optimizations/deoptimize_elimination.h"
20 #include "optimizer/optimizations/cleanup.h"
21 #include "optimizer/ir/runtime_interface.h"
22 
23 namespace ark::compiler {
24 class DeoptimizeEliminationTest : public CommonTest {
25 public:
DeoptimizeEliminationTest()26     DeoptimizeEliminationTest()
27         : graph_(CreateGraphStartEndBlocks()),
28           defaultCompilerSafePointsRequireRegMap_(g_options.IsCompilerSafePointsRequireRegMap())
29     {
30     }
31 
~DeoptimizeEliminationTest()32     ~DeoptimizeEliminationTest() override
33     {
34         g_options.SetCompilerSafePointsRequireRegMap(defaultCompilerSafePointsRequireRegMap_);
35     }
36 
37     NO_COPY_SEMANTIC(DeoptimizeEliminationTest);
38     NO_MOVE_SEMANTIC(DeoptimizeEliminationTest);
39 
GetGraph()40     Graph *GetGraph()
41     {
42         return graph_;
43     }
44 
45 private:
46     Graph *graph_ {nullptr};
47     bool defaultCompilerSafePointsRequireRegMap_;
48 };
49 
50 // NOLINTBEGIN(readability-magic-numbers)
TEST_F(DeoptimizeEliminationTest,DeoptimizeIfTest)51 TEST_F(DeoptimizeEliminationTest, DeoptimizeIfTest)
52 {
53     GRAPH(GetGraph())
54     {
55         PARAMETER(0U, 0U).s32();
56         CONSTANT(1U, 0U);
57         BASIC_BLOCK(2U, 1U)
58         {
59             // cleanup delete this
60             INST(10U, Opcode::SaveState).Inputs(1U).SrcVregs({1U});
61 
62             INST(3U, Opcode::SaveStateDeoptimize).Inputs(1U).SrcVregs({1U});
63             INST(4U, Opcode::Compare).b().Inputs(0U, 1U).CC(CC_GT);
64             INST(5U, Opcode::DeoptimizeIf).Inputs(4U, 3U);
65             // 5 is dominate by 7
66             INST(6U, Opcode::SaveStateDeoptimize).Inputs(1U).SrcVregs({1U});
67             INST(7U, Opcode::DeoptimizeIf).Inputs(4U, 6U);
68 
69             // redundant
70             INST(8U, Opcode::DeoptimizeIf).Inputs(1U, 6U);
71 
72             INST(9U, Opcode::ReturnVoid).v0id();
73         }
74     }
75     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
76     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
77     auto graph = CreateEmptyGraph();
78     GRAPH(graph)
79     {
80         PARAMETER(0U, 0U).s32();
81         CONSTANT(1U, 0U);
82         BASIC_BLOCK(2U, 1U)
83         {
84             INST(3U, Opcode::SaveStateDeoptimize).Inputs(1U).SrcVregs({1U});
85             INST(4U, Opcode::Compare).b().Inputs(0U, 1U).CC(CC_GT);
86             INST(5U, Opcode::DeoptimizeIf).Inputs(4U, 3U);
87 
88             INST(9U, Opcode::ReturnVoid).v0id();
89         }
90     }
91     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
92 }
93 
TEST_F(DeoptimizeEliminationTest,ChaGuardOneBlockTest)94 TEST_F(DeoptimizeEliminationTest, ChaGuardOneBlockTest)
95 {
96     GRAPH(GetGraph())
97     {
98         CONSTANT(10U, 0U);
99         BASIC_BLOCK(2U, 1U)
100         {
101             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
102             INST(1U, Opcode::IsMustDeoptimize).b();
103             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
104 
105             INST(3U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
106             INST(4U, Opcode::IsMustDeoptimize).b();
107             INST(5U, Opcode::DeoptimizeIf).Inputs(4U, 3U);
108 
109             INST(9U, Opcode::ReturnVoid).v0id();
110         }
111     }
112     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
113     auto graph = CreateEmptyGraph();
114     GRAPH(graph)
115     {
116         CONSTANT(10U, 0U);
117         BASIC_BLOCK(2U, 1U)
118         {
119             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
120             INST(1U, Opcode::IsMustDeoptimize).b();
121             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
122 
123             INST(3U, Opcode::NOP);
124             INST(4U, Opcode::NOP);
125             INST(5U, Opcode::NOP);
126 
127             INST(9U, Opcode::ReturnVoid).v0id();
128         }
129     }
130     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
131 }
132 
TEST_F(DeoptimizeEliminationTest,ChaGuardOneBlockCallTest)133 TEST_F(DeoptimizeEliminationTest, ChaGuardOneBlockCallTest)
134 {
135     // Not applied. Call to runtime between guards.
136     GRAPH(GetGraph())
137     {
138         CONSTANT(10U, 0U);
139         BASIC_BLOCK(2U, 1U)
140         {
141             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
142             INST(1U, Opcode::IsMustDeoptimize).b();
143             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
144             INST(20U, Opcode::SaveState).NoVregs();
145             INST(6U, Opcode::CallStatic).v0id().InputsAutoType(20U);
146 
147             INST(3U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
148             INST(4U, Opcode::IsMustDeoptimize).b();
149             INST(5U, Opcode::DeoptimizeIf).Inputs(4U, 3U);
150 
151             INST(9U, Opcode::ReturnVoid).v0id();
152         }
153     }
154     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
155     ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
156     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
157 }
158 
TEST_F(DeoptimizeEliminationTest,ChaGuardOneBlockSeveralGuardsTest)159 TEST_F(DeoptimizeEliminationTest, ChaGuardOneBlockSeveralGuardsTest)
160 {
161     GRAPH(GetGraph())
162     {
163         CONSTANT(10U, 0U);
164         BASIC_BLOCK(2U, 1U)
165         {
166             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
167             INST(1U, Opcode::IsMustDeoptimize).b();
168             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
169             INST(20U, Opcode::SaveState).NoVregs();
170             INST(6U, Opcode::CallStatic).v0id().InputsAutoType(20U);
171 
172             INST(3U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
173             INST(4U, Opcode::IsMustDeoptimize).b();
174             INST(5U, Opcode::DeoptimizeIf).Inputs(4U, 3U);
175 
176             INST(11U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
177             INST(12U, Opcode::IsMustDeoptimize).b();
178             INST(13U, Opcode::DeoptimizeIf).Inputs(12U, 11U);
179 
180             INST(9U, Opcode::ReturnVoid).v0id();
181         }
182     }
183     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
184     auto graph = CreateEmptyGraph();
185     GRAPH(graph)
186     {
187         CONSTANT(10U, 0U);
188         BASIC_BLOCK(2U, 1U)
189         {
190             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
191             INST(1U, Opcode::IsMustDeoptimize).b();
192             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
193             INST(20U, Opcode::SaveState).NoVregs();
194             INST(6U, Opcode::CallStatic).v0id().InputsAutoType(20U);
195 
196             INST(3U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
197             INST(4U, Opcode::IsMustDeoptimize).b();
198             INST(5U, Opcode::DeoptimizeIf).Inputs(4U, 3U);
199 
200             INST(11U, Opcode::NOP);
201             INST(12U, Opcode::NOP);
202             INST(13U, Opcode::NOP);
203 
204             INST(9U, Opcode::ReturnVoid).v0id();
205         }
206     }
207     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
208 }
209 
TEST_F(DeoptimizeEliminationTest,ChaGuardOneBlockCallInlinedTest)210 TEST_F(DeoptimizeEliminationTest, ChaGuardOneBlockCallInlinedTest)
211 {
212     GRAPH(GetGraph())
213     {
214         CONSTANT(10U, 0U);
215         BASIC_BLOCK(2U, 1U)
216         {
217             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
218             INST(1U, Opcode::IsMustDeoptimize).b();
219             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
220             INST(20U, Opcode::SaveState).NoVregs();
221             INST(6U, Opcode::CallStatic).v0id().Inlined().InputsAutoType(20U);
222             INST(7U, Opcode::ReturnInlined).Inputs(20U);
223 
224             INST(3U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
225             INST(4U, Opcode::IsMustDeoptimize).b();
226             INST(5U, Opcode::DeoptimizeIf).Inputs(4U, 3U);
227 
228             INST(9U, Opcode::ReturnVoid).v0id();
229         }
230     }
231     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
232     auto graph = CreateEmptyGraph();
233     GRAPH(graph)
234     {
235         CONSTANT(10U, 0U);
236         BASIC_BLOCK(2U, 1U)
237         {
238             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U).SrcVregs({10U});
239             INST(1U, Opcode::IsMustDeoptimize).b();
240             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
241             INST(20U, Opcode::SaveState).NoVregs();
242             INST(6U, Opcode::CallStatic).v0id().Inlined().InputsAutoType(20U);
243             INST(7U, Opcode::ReturnInlined).Inputs(20U);
244 
245             INST(3U, Opcode::NOP);
246             INST(4U, Opcode::NOP);
247             INST(5U, Opcode::NOP);
248 
249             INST(9U, Opcode::ReturnVoid).v0id();
250         }
251     }
252     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
253 }
254 
TEST_F(DeoptimizeEliminationTest,ChaGuardIfTest)255 TEST_F(DeoptimizeEliminationTest, ChaGuardIfTest)
256 {
257     /*
258      * Not applied.
259      * bb1
260      * guard
261      * |   \
262      * |   bb2
263      * |   runtime call
264      * |  /
265      * bb3
266      * guard
267      */
268     GRAPH(GetGraph())
269     {
270         PARAMETER(10U, 0U).s32();
271         CONSTANT(11U, 1U);
272         BASIC_BLOCK(2U, 4U, 5U)
273         {
274             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
275             INST(1U, Opcode::IsMustDeoptimize).b();
276             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
277             INST(3U, Opcode::Compare).b().CC(CC_LT).Inputs(10U, 11U);
278             INST(4U, Opcode::IfImm).CC(CC_NE).Inputs(3U).Imm(0U);
279         }
280         BASIC_BLOCK(4U, 5U)
281         {
282             INST(20U, Opcode::SaveState).NoVregs();
283             INST(5U, Opcode::CallStatic).v0id().InputsAutoType(20U);
284         }
285         BASIC_BLOCK(5U, 1U)
286         {
287             INST(6U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
288             INST(7U, Opcode::IsMustDeoptimize).b();
289             INST(8U, Opcode::DeoptimizeIf).Inputs(7U, 6U);
290             INST(9U, Opcode::ReturnVoid).v0id();
291         }
292     }
293     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
294     ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
295     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
296 }
297 
SRC_GRAPH(ChaGuardIfSeveralGuardsTest,Graph * graph)298 SRC_GRAPH(ChaGuardIfSeveralGuardsTest, Graph *graph)
299 {
300     GRAPH(graph)
301     {
302         PARAMETER(10U, 0U).s32();
303         CONSTANT(11U, 1U);
304         BASIC_BLOCK(2U, 4U, 5U)
305         {
306             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
307             INST(1U, Opcode::IsMustDeoptimize).b();
308             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
309             INST(20U, Opcode::SaveState).NoVregs();
310             INST(12U, Opcode::CallStatic).v0id().InputsAutoType(20U);
311             INST(13U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
312             INST(14U, Opcode::IsMustDeoptimize).b();
313             INST(15U, Opcode::DeoptimizeIf).Inputs(14U, 13U);
314             INST(3U, Opcode::Compare).b().CC(CC_LT).Inputs(10U, 11U);
315             INST(4U, Opcode::IfImm).CC(CC_NE).Inputs(3U).Imm(0U);
316         }
317         BASIC_BLOCK(4U, 5U)
318         {
319             INST(21U, Opcode::SaveState).NoVregs();
320             INST(5U, Opcode::CallStatic).v0id().Inlined().InputsAutoType(21U);
321             INST(16U, Opcode::ReturnInlined).Inputs(21U);
322         }
323         BASIC_BLOCK(5U, 1U)
324         {
325             INST(6U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
326             INST(7U, Opcode::IsMustDeoptimize).b();
327             INST(8U, Opcode::DeoptimizeIf).Inputs(7U, 6U);
328             INST(9U, Opcode::ReturnVoid).v0id();
329         }
330     }
331 }
332 
OUT_GRAPH(ChaGuardIfSeveralGuardsTest,Graph * graph)333 OUT_GRAPH(ChaGuardIfSeveralGuardsTest, Graph *graph)
334 {
335     GRAPH(graph)
336     {
337         PARAMETER(10U, 0U).s32();
338         CONSTANT(11U, 1U);
339         BASIC_BLOCK(2U, 4U, 5U)
340         {
341             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
342             INST(1U, Opcode::IsMustDeoptimize).b();
343             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
344             INST(20U, Opcode::SaveState).NoVregs();
345             INST(12U, Opcode::CallStatic).v0id().InputsAutoType(20U);
346             INST(13U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
347             INST(14U, Opcode::IsMustDeoptimize).b();
348             INST(15U, Opcode::DeoptimizeIf).Inputs(14U, 13U);
349             INST(3U, Opcode::Compare).b().CC(CC_LT).Inputs(10U, 11U);
350             INST(4U, Opcode::IfImm).CC(CC_NE).Inputs(3U).Imm(0U);
351         }
352         BASIC_BLOCK(4U, 5U)
353         {
354             INST(21U, Opcode::SaveState).NoVregs();
355             INST(5U, Opcode::CallStatic).v0id().Inlined().InputsAutoType(21U);
356             INST(16U, Opcode::ReturnInlined).Inputs(21U);
357         }
358         BASIC_BLOCK(5U, 1U)
359         {
360             INST(6U, Opcode::NOP);
361             INST(7U, Opcode::NOP);
362             INST(8U, Opcode::NOP);
363             INST(9U, Opcode::ReturnVoid).v0id();
364         }
365     }
366 }
367 
TEST_F(DeoptimizeEliminationTest,ChaGuardIfSeveralGuardsTest)368 TEST_F(DeoptimizeEliminationTest, ChaGuardIfSeveralGuardsTest)
369 {
370     /*
371      * bb1
372      * guard
373      * call
374      * guard
375      * |   \
376      * |   bb2
377      * |   some inst
378      * |  /
379      * bb3
380      * guard
381      */
382     src_graph::ChaGuardIfSeveralGuardsTest::CREATE(GetGraph());
383     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
384     auto graph = CreateEmptyGraph();
385     out_graph::ChaGuardIfSeveralGuardsTest::CREATE(graph);
386     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
387 }
388 
SRC_GRAPH(ChaGuardLoopTest,Graph * graph)389 SRC_GRAPH(ChaGuardLoopTest, Graph *graph)
390 {
391     GRAPH(graph)
392     {
393         CONSTANT(10U, 0U);
394         CONSTANT(11U, 1U);
395         CONSTANT(12U, 10U);
396         BASIC_BLOCK(2U, 3U)
397         {
398             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
399             INST(1U, Opcode::IsMustDeoptimize).b();
400             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
401         }
402         BASIC_BLOCK(3U, 4U, 5U)
403         {
404             INST(3U, Opcode::Phi).s32().Inputs(10U, 7U);
405             INST(8U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 12U);
406             INST(9U, Opcode::IfImm).CC(CC_NE).Inputs(8U).Imm(0U);
407         }
408         BASIC_BLOCK(4U, 3U)
409         {
410             INST(4U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
411             INST(5U, Opcode::IsMustDeoptimize).b();
412             INST(6U, Opcode::DeoptimizeIf).Inputs(5U, 4U);
413             INST(7U, Opcode::Add).s32().Inputs(3U, 11U);
414         }
415         BASIC_BLOCK(5U, 1U)
416         {
417             INST(13U, Opcode::Return).s32().Inputs(3U);
418         }
419     }
420 }
421 
OUT_GRAPH(ChaGuardLoopTest,Graph * graph)422 OUT_GRAPH(ChaGuardLoopTest, Graph *graph)
423 {
424     GRAPH(graph)
425     {
426         CONSTANT(10U, 0U);
427         CONSTANT(11U, 1U);
428         CONSTANT(12U, 10U);
429         BASIC_BLOCK(2U, 3U)
430         {
431             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
432             INST(1U, Opcode::IsMustDeoptimize).b();
433             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
434         }
435         BASIC_BLOCK(3U, 4U, 5U)
436         {
437             INST(3U, Opcode::Phi).s32().Inputs(10U, 7U);
438             INST(8U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 12U);
439             INST(9U, Opcode::IfImm).CC(CC_NE).Inputs(8U).Imm(0U);
440         }
441         BASIC_BLOCK(4U, 3U)
442         {
443             INST(4U, Opcode::NOP);
444             INST(5U, Opcode::NOP);
445             INST(6U, Opcode::NOP);
446             INST(7U, Opcode::Add).s32().Inputs(3U, 11U);
447         }
448         BASIC_BLOCK(5U, 1U)
449         {
450             INST(13U, Opcode::Return).s32().Inputs(3U);
451         }
452     }
453 }
454 
TEST_F(DeoptimizeEliminationTest,ChaGuardLoopTest)455 TEST_F(DeoptimizeEliminationTest, ChaGuardLoopTest)
456 {
457     src_graph::ChaGuardLoopTest::CREATE(GetGraph());
458     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
459     auto graph = CreateEmptyGraph();
460     out_graph::ChaGuardLoopTest::CREATE(graph);
461     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
462 }
463 
TEST_F(DeoptimizeEliminationTest,ChaGuardLoopWithCallAfterGuardTest)464 TEST_F(DeoptimizeEliminationTest, ChaGuardLoopWithCallAfterGuardTest)
465 {
466     GRAPH(GetGraph())
467     {
468         CONSTANT(10U, 0U);
469         CONSTANT(11U, 1U);
470         CONSTANT(12U, 10U);
471         BASIC_BLOCK(2U, 3U)
472         {
473             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
474             INST(1U, Opcode::IsMustDeoptimize).b();
475             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
476         }
477         BASIC_BLOCK(3U, 4U, 5U)
478         {
479             INST(3U, Opcode::Phi).s32().Inputs(10U, 7U);
480             INST(8U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 12U);
481             INST(9U, Opcode::IfImm).CC(CC_NE).Inputs(8U).Imm(0U);
482         }
483         BASIC_BLOCK(4U, 3U)
484         {
485             INST(4U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
486             INST(5U, Opcode::IsMustDeoptimize).b();
487             INST(6U, Opcode::DeoptimizeIf).Inputs(5U, 4U);
488             INST(20U, Opcode::SaveState).NoVregs();
489             INST(14U, Opcode::CallStatic).v0id().InputsAutoType(20U);
490             INST(7U, Opcode::Add).s32().Inputs(3U, 11U);
491         }
492         BASIC_BLOCK(5U, 1U)
493         {
494             INST(13U, Opcode::Return).s32().Inputs(3U);
495         }
496     }
497     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
498     ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
499     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
500 }
501 
TEST_F(DeoptimizeEliminationTest,ChaGuardLoopWithCallBeforeGuardTest)502 TEST_F(DeoptimizeEliminationTest, ChaGuardLoopWithCallBeforeGuardTest)
503 {
504     GRAPH(GetGraph())
505     {
506         CONSTANT(10U, 0U);
507         CONSTANT(11U, 1U);
508         CONSTANT(12U, 10U);
509         BASIC_BLOCK(2U, 3U)
510         {
511             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
512             INST(1U, Opcode::IsMustDeoptimize).b();
513             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
514         }
515         BASIC_BLOCK(3U, 4U, 5U)
516         {
517             INST(3U, Opcode::Phi).s32().Inputs(10U, 7U);
518             INST(8U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 12U);
519             INST(9U, Opcode::IfImm).CC(CC_NE).Inputs(8U).Imm(0U);
520         }
521         BASIC_BLOCK(4U, 3U)
522         {
523             INST(20U, Opcode::SaveState).NoVregs();
524             INST(14U, Opcode::CallStatic).v0id().InputsAutoType(20U);
525             INST(4U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
526             INST(5U, Opcode::IsMustDeoptimize).b();
527             INST(6U, Opcode::DeoptimizeIf).Inputs(5U, 4U);
528             INST(7U, Opcode::Add).s32().Inputs(3U, 11U);
529         }
530         BASIC_BLOCK(5U, 1U)
531         {
532             INST(13U, Opcode::Return).s32().Inputs(3U);
533         }
534     }
535     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
536     ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
537     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
538 }
539 
SRC_GRAPH(ChaGuardLoopWithCallBetweenGuardsWithDomGuardTest,Graph * graph)540 SRC_GRAPH(ChaGuardLoopWithCallBetweenGuardsWithDomGuardTest, Graph *graph)
541 {
542     GRAPH(graph)
543     {
544         CONSTANT(10U, 0U);
545         CONSTANT(11U, 1U);
546         CONSTANT(12U, 10U);
547         BASIC_BLOCK(2U, 3U)
548         {
549             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
550             INST(1U, Opcode::IsMustDeoptimize).b();
551             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
552         }
553         BASIC_BLOCK(3U, 4U, 5U)
554         {
555             INST(3U, Opcode::Phi).s32().Inputs(10U, 7U);
556             INST(8U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 12U);
557             INST(9U, Opcode::IfImm).CC(CC_NE).Inputs(8U).Imm(0U);
558         }
559         BASIC_BLOCK(4U, 3U)
560         {
561             INST(15U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
562             INST(16U, Opcode::IsMustDeoptimize).b();
563             INST(17U, Opcode::DeoptimizeIf).Inputs(16U, 15U);
564             INST(20U, Opcode::SaveState).NoVregs();
565             INST(14U, Opcode::CallStatic).v0id().InputsAutoType(20U);
566             INST(4U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
567             INST(5U, Opcode::IsMustDeoptimize).b();
568             INST(6U, Opcode::DeoptimizeIf).Inputs(5U, 4U);
569             INST(7U, Opcode::Add).s32().Inputs(3U, 11U);
570         }
571         BASIC_BLOCK(5U, 1U)
572         {
573             INST(13U, Opcode::Return).s32().Inputs(3U);
574         }
575     }
576 }
577 
OUT_GRAPH(ChaGuardLoopWithCallBetweenGuardsWithDomGuardTest,Graph * graph)578 OUT_GRAPH(ChaGuardLoopWithCallBetweenGuardsWithDomGuardTest, Graph *graph)
579 {
580     GRAPH(graph)
581     {
582         CONSTANT(10U, 0U);
583         CONSTANT(11U, 1U);
584         CONSTANT(12U, 10U);
585         BASIC_BLOCK(2U, 3U)
586         {
587             INST(0U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
588             INST(1U, Opcode::IsMustDeoptimize).b();
589             INST(2U, Opcode::DeoptimizeIf).Inputs(1U, 0U);
590         }
591         BASIC_BLOCK(3U, 4U, 5U)
592         {
593             INST(3U, Opcode::Phi).s32().Inputs(10U, 7U);
594             INST(8U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 12U);
595             INST(9U, Opcode::IfImm).CC(CC_NE).Inputs(8U).Imm(0U);
596         }
597         BASIC_BLOCK(4U, 3U)
598         {
599             INST(15U, Opcode::NOP);
600             INST(16U, Opcode::NOP);
601             INST(17U, Opcode::NOP);
602             INST(20U, Opcode::SaveState).NoVregs();
603             INST(14U, Opcode::CallStatic).v0id().InputsAutoType(20U);
604             INST(4U, Opcode::SaveStateDeoptimize).Inputs(10U, 11U).SrcVregs({0U, 1U});
605             INST(5U, Opcode::IsMustDeoptimize).b();
606             INST(6U, Opcode::DeoptimizeIf).Inputs(5U, 4U);
607             INST(7U, Opcode::Add).s32().Inputs(3U, 11U);
608         }
609         BASIC_BLOCK(5U, 1U)
610         {
611             INST(13U, Opcode::Return).s32().Inputs(3U);
612         }
613     }
614 }
615 
TEST_F(DeoptimizeEliminationTest,ChaGuardLoopWithCallBetweenGuardsWithDomGuardTest)616 TEST_F(DeoptimizeEliminationTest, ChaGuardLoopWithCallBetweenGuardsWithDomGuardTest)
617 {
618     src_graph::ChaGuardLoopWithCallBetweenGuardsWithDomGuardTest::CREATE(GetGraph());
619     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
620     auto graph = CreateEmptyGraph();
621     out_graph::ChaGuardLoopWithCallBetweenGuardsWithDomGuardTest::CREATE(graph);
622     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
623 }
624 
SRC_GRAPH(ChaGuardLoopWithDuplicatedGuardsTest,Graph * graph)625 SRC_GRAPH(ChaGuardLoopWithDuplicatedGuardsTest, Graph *graph)
626 {
627     GRAPH(graph)
628     {
629         CONSTANT(0U, 0U);
630         CONSTANT(1U, 1U);
631         PARAMETER(2U, 0U).s32();
632         BASIC_BLOCK(2U, 3U, 10U)
633         {
634             INST(3U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 2U);
635             INST(4U, Opcode::IfImm).CC(CC_NE).Inputs(3U).Imm(0U);
636         }
637         BASIC_BLOCK(3U, 4U, 5U)
638         {
639             INST(19U, Opcode::Phi).s32().Inputs(0U, 14U);
640             INST(5U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
641             INST(6U, Opcode::IsMustDeoptimize).b();
642             INST(7U, Opcode::DeoptimizeIf).Inputs(6U, 5U);
643             INST(8U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 2U);
644             INST(9U, Opcode::IfImm).CC(CC_NE).Inputs(8U).Imm(0U);
645         }
646         BASIC_BLOCK(4U, 5U)
647         {
648             INST(10U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
649             INST(11U, Opcode::IsMustDeoptimize).b();
650             INST(12U, Opcode::DeoptimizeIf).Inputs(11U, 10U);
651         }
652         BASIC_BLOCK(5U, 3U, 10U)
653         {
654             INST(20U, Opcode::SaveState).NoVregs();
655             INST(13U, Opcode::CallStatic).v0id().InputsAutoType(20U);
656             INST(14U, Opcode::Add).s32().Inputs(19U, 1U);
657             INST(15U, Opcode::Compare).b().CC(CC_LT).Inputs(14U, 2U);
658             INST(16U, Opcode::IfImm).CC(CC_NE).Inputs(15U).Imm(0U);
659         }
660 
661         BASIC_BLOCK(10U, 1U)
662         {
663             INST(17U, Opcode::Phi).s32().Inputs(0U, 14U);
664             INST(18U, Opcode::Return).s32().Inputs(17U);
665         }
666     }
667 }
668 
OUT_GRAPH(ChaGuardLoopWithDuplicatedGuardsTest,Graph * graph)669 OUT_GRAPH(ChaGuardLoopWithDuplicatedGuardsTest, Graph *graph)
670 {
671     GRAPH(graph)
672     {
673         CONSTANT(0U, 0U);
674         CONSTANT(1U, 1U);
675         PARAMETER(2U, 0U).s32();
676         BASIC_BLOCK(2U, 3U, 10U)
677         {
678             INST(3U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 2U);
679             INST(4U, Opcode::IfImm).CC(CC_NE).Inputs(3U).Imm(0U);
680         }
681         BASIC_BLOCK(3U, 4U, 5U)
682         {
683             INST(19U, Opcode::Phi).s32().Inputs(0U, 14U);
684             INST(5U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
685             INST(6U, Opcode::IsMustDeoptimize).b();
686             INST(7U, Opcode::DeoptimizeIf).Inputs(6U, 5U);
687             INST(8U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 2U);
688             INST(9U, Opcode::IfImm).CC(CC_NE).Inputs(8U).Imm(0U);
689         }
690         BASIC_BLOCK(4U, 5U)
691         {
692             INST(10U, Opcode::NOP);
693             INST(11U, Opcode::NOP);
694             INST(12U, Opcode::NOP);
695         }
696         BASIC_BLOCK(5U, 3U, 10U)
697         {
698             INST(20U, Opcode::SaveState).NoVregs();
699             INST(13U, Opcode::CallStatic).v0id().InputsAutoType(20U);
700             INST(14U, Opcode::Add).s32().Inputs(19U, 1U);
701             INST(15U, Opcode::Compare).b().CC(CC_LT).Inputs(14U, 2U);
702             INST(16U, Opcode::IfImm).CC(CC_NE).Inputs(15U).Imm(0U);
703         }
704 
705         BASIC_BLOCK(10U, 1U)
706         {
707             INST(17U, Opcode::Phi).s32().Inputs(0U, 14U);
708             INST(18U, Opcode::Return).s32().Inputs(17U);
709         }
710     }
711 }
712 
TEST_F(DeoptimizeEliminationTest,ChaGuardLoopWithDuplicatedGuardsTest)713 TEST_F(DeoptimizeEliminationTest, ChaGuardLoopWithDuplicatedGuardsTest)
714 {
715     src_graph::ChaGuardLoopWithDuplicatedGuardsTest::CREATE(GetGraph());
716     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
717     auto graph = CreateEmptyGraph();
718     out_graph::ChaGuardLoopWithDuplicatedGuardsTest::CREATE(graph);
719     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
720 }
721 
TEST_F(DeoptimizeEliminationTest,ChaGuardNotDominateTest)722 TEST_F(DeoptimizeEliminationTest, ChaGuardNotDominateTest)
723 {
724     GRAPH(GetGraph())
725     {
726         PARAMETER(0U, 0U).s32();
727         PARAMETER(1U, 1U).s32();
728         BASIC_BLOCK(2U, 3U, 4U)
729         {
730             INST(2U, Opcode::Compare).b().CC(CC_EQ).Inputs(0U, 1U);
731             INST(3U, Opcode::IfImm).CC(CC_NE).Inputs(2U).Imm(0U);
732         }
733         BASIC_BLOCK(3U, 4U)
734         {
735             INST(4U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U).SrcVregs({0U, 1U});
736             INST(5U, Opcode::IsMustDeoptimize).b();
737             INST(6U, Opcode::DeoptimizeIf).Inputs(5U, 4U);
738         }
739         BASIC_BLOCK(4U, 1U)
740         {
741             INST(7U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U).SrcVregs({0U, 1U});
742             INST(8U, Opcode::IsMustDeoptimize).b();
743             INST(9U, Opcode::DeoptimizeIf).Inputs(8U, 7U);
744             INST(10U, Opcode::ReturnVoid).v0id();
745         }
746     }
747     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
748     ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
749     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
750 }
751 
SRC_GRAPH(ChaGuardIfWithGuardsTest,Graph * graph)752 SRC_GRAPH(ChaGuardIfWithGuardsTest, Graph *graph)
753 {
754     GRAPH(graph)
755     {
756         PARAMETER(0U, 0U).s32();
757         PARAMETER(1U, 1U).s32();
758         BASIC_BLOCK(2U, 3U, 4U)
759         {
760             INST(5U, Opcode::Compare).b().CC(CC_EQ).Inputs(0U, 1U);
761             INST(6U, Opcode::IfImm).CC(CC_NE).Inputs(5U).Imm(0U);
762         }
763         BASIC_BLOCK(3U, 5U)
764         {
765             INST(20U, Opcode::SaveState).NoVregs();
766             INST(7U, Opcode::CallStatic).v0id().InputsAutoType(20U);
767             INST(8U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U).SrcVregs({0U, 1U});
768             INST(9U, Opcode::IsMustDeoptimize).b();
769             INST(10U, Opcode::DeoptimizeIf).Inputs(9U, 8U);
770         }
771         BASIC_BLOCK(4U, 5U)
772         {
773             INST(21U, Opcode::SaveState).NoVregs();
774             INST(11U, Opcode::CallStatic).v0id().InputsAutoType(21U);
775             INST(12U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U).SrcVregs({0U, 1U});
776             INST(13U, Opcode::IsMustDeoptimize).b();
777             INST(14U, Opcode::DeoptimizeIf).Inputs(13U, 12U);
778         }
779         BASIC_BLOCK(5U, 1U)
780         {
781             INST(15U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U).SrcVregs({0U, 1U});
782             INST(16U, Opcode::IsMustDeoptimize).b();
783             INST(17U, Opcode::DeoptimizeIf).Inputs(16U, 15U);
784             INST(18U, Opcode::ReturnVoid).v0id();
785         }
786     }
787 }
788 
OUT_GRAPH(ChaGuardIfWithGuardsTest,Graph * graph)789 OUT_GRAPH(ChaGuardIfWithGuardsTest, Graph *graph)
790 {
791     GRAPH(graph)
792     {
793         PARAMETER(0U, 0U).s32();
794         PARAMETER(1U, 1U).s32();
795         BASIC_BLOCK(2U, 3U, 4U)
796         {
797             INST(5U, Opcode::Compare).b().CC(CC_EQ).Inputs(0U, 1U);
798             INST(6U, Opcode::IfImm).CC(CC_NE).Inputs(5U).Imm(0U);
799         }
800         BASIC_BLOCK(3U, 5U)
801         {
802             INST(20U, Opcode::SaveState).NoVregs();
803             INST(7U, Opcode::CallStatic).v0id().InputsAutoType(20U);
804             INST(8U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U).SrcVregs({0U, 1U});
805             INST(9U, Opcode::IsMustDeoptimize).b();
806             INST(10U, Opcode::DeoptimizeIf).Inputs(9U, 8U);
807         }
808         BASIC_BLOCK(4U, 5U)
809         {
810             INST(21U, Opcode::SaveState).NoVregs();
811             INST(11U, Opcode::CallStatic).v0id().InputsAutoType(21U);
812             INST(12U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U).SrcVregs({0U, 1U});
813             INST(13U, Opcode::IsMustDeoptimize).b();
814             INST(14U, Opcode::DeoptimizeIf).Inputs(13U, 12U);
815         }
816         BASIC_BLOCK(5U, 1U)
817         {
818             INST(15U, Opcode::NOP);
819             INST(16U, Opcode::NOP);
820             INST(17U, Opcode::NOP);
821             INST(18U, Opcode::ReturnVoid).v0id();
822         }
823     }
824 }
825 
TEST_F(DeoptimizeEliminationTest,ChaGuardIfWithGuardsTest)826 TEST_F(DeoptimizeEliminationTest, ChaGuardIfWithGuardsTest)
827 {
828     /*
829      *    some code
830      *    /       \
831      *  call     call
832      * guard    guard
833      * \          /
834      *  \        /
835      *    guard(*, deleted)
836      */
837     src_graph::ChaGuardIfWithGuardsTest::CREATE(GetGraph());
838     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
839     auto graph = CreateEmptyGraph();
840     out_graph::ChaGuardIfWithGuardsTest::CREATE(graph);
841     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
842 }
843 
TEST_F(DeoptimizeEliminationTest,ReplaceByDeoptimizeTest)844 TEST_F(DeoptimizeEliminationTest, ReplaceByDeoptimizeTest)
845 {
846     GRAPH(GetGraph())
847     {
848         CONSTANT(0U, 1U);
849         BASIC_BLOCK(2U, 1U)
850         {
851             INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
852             INST(3U, Opcode::DeoptimizeIf).Inputs(0U, 2U);
853             INST(4U, Opcode::ReturnVoid).v0id();
854         }
855     }
856     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
857     auto graph = CreateEmptyGraph();
858     GRAPH(graph)
859     {
860         CONSTANT(0U, 1U);
861         BASIC_BLOCK(2U, 1U)
862         {
863             INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
864             INST(3U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::INVALID).Inputs(2U);
865         }
866     }
867     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
868 }
869 
TEST_F(DeoptimizeEliminationTest,ReplaceByDeoptimizeInliningTest)870 TEST_F(DeoptimizeEliminationTest, ReplaceByDeoptimizeInliningTest)
871 {
872     GRAPH(GetGraph())
873     {
874         CONSTANT(0U, 1U);
875         BASIC_BLOCK(2U, 1U)
876         {
877             INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
878             INST(3U, Opcode::CallStatic).v0id().InputsAutoType(2U).Inlined();
879             INST(4U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
880             INST(7U, Opcode::DeoptimizeIf).Inputs(0U, 4U);
881             INST(5U, Opcode::ReturnInlined).Inputs(2U);
882             INST(6U, Opcode::ReturnVoid).v0id();
883         }
884     }
885     INS(4U).CastToSaveState()->SetCallerInst(static_cast<CallInst *>(&INS(3U)));
886     INS(4U).CastToSaveState()->SetInliningDepth(1U);
887 
888     ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
889 
890     auto graph = CreateEmptyGraph();
891     GRAPH(graph)
892     {
893         CONSTANT(0U, 1U);
894         BASIC_BLOCK(2U, 1U)
895         {
896             INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
897             INST(3U, Opcode::CallStatic).v0id().InputsAutoType(2U).Inlined();
898             INST(4U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
899             INST(5U, Opcode::ReturnInlined).Inputs(2U);
900             INST(8U, Opcode::Deoptimize).Inputs(4U);
901         }
902     }
903     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
904 }
905 
906 // NOLINTEND(readability-magic-numbers)
907 
908 }  // namespace ark::compiler
909