1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "unit_test.h"
17 #include "optimizer/ir/graph_cloner.h"
18 #include "optimizer/optimizations/deoptimize_elimination.h"
19 #include "optimizer/optimizations/cleanup.h"
20 #include "optimizer/ir/runtime_interface.h"
21
22 namespace panda::compiler {
23 class DeoptimizeEliminationTest : public CommonTest {
24 public:
DeoptimizeEliminationTest()25 DeoptimizeEliminationTest() : graph_(CreateGraphStartEndBlocks()) {}
26
GetGraph()27 Graph *GetGraph()
28 {
29 return graph_;
30 }
31
32 protected:
33 Graph *graph_ {nullptr};
34 };
35
TEST_F(DeoptimizeEliminationTest,DeoptimizeIfTest)36 TEST_F(DeoptimizeEliminationTest, DeoptimizeIfTest)
37 {
38 GRAPH(GetGraph())
39 {
40 PARAMETER(0, 0).s32();
41 CONSTANT(1, 0);
42 BASIC_BLOCK(2, 1)
43 {
44 // without users
45 INST(2, Opcode::SaveStateDeoptimize).Inputs(1).SrcVregs({1});
46 // cleanup delete this
47 INST(10, Opcode::SaveState).Inputs(1).SrcVregs({1});
48
49 INST(3, Opcode::SaveStateDeoptimize).Inputs(1).SrcVregs({1});
50 INST(4, Opcode::Compare).b().Inputs(0, 1).CC(CC_GT);
51 INST(5, Opcode::DeoptimizeIf).Inputs(4, 3);
52 // 5 is dominate by 7
53 INST(6, Opcode::SaveStateDeoptimize).Inputs(1).SrcVregs({1});
54 INST(7, Opcode::DeoptimizeIf).Inputs(4, 6);
55
56 // redundant
57 INST(8, Opcode::DeoptimizeIf).Inputs(1, 6);
58
59 INST(9, Opcode::ReturnVoid).v0id();
60 }
61 }
62 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
63 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
64 auto graph = CreateEmptyGraph();
65 GRAPH(graph)
66 {
67 PARAMETER(0, 0).s32();
68 CONSTANT(1, 0);
69 BASIC_BLOCK(2, 1)
70 {
71 INST(3, Opcode::SaveStateDeoptimize).Inputs(1).SrcVregs({1});
72 INST(4, Opcode::Compare).b().Inputs(0, 1).CC(CC_GT);
73 INST(5, Opcode::DeoptimizeIf).Inputs(4, 3);
74
75 INST(9, Opcode::ReturnVoid).v0id();
76 }
77 }
78 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
79 }
80
TEST_F(DeoptimizeEliminationTest,ChaGuardOneBlockTest)81 TEST_F(DeoptimizeEliminationTest, ChaGuardOneBlockTest)
82 {
83 GRAPH(GetGraph())
84 {
85 CONSTANT(10, 0);
86 BASIC_BLOCK(2, 1)
87 {
88 INST(0, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
89 INST(1, Opcode::IsMustDeoptimize).b();
90 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
91
92 INST(3, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
93 INST(4, Opcode::IsMustDeoptimize).b();
94 INST(5, Opcode::DeoptimizeIf).Inputs(4, 3);
95
96 INST(9, Opcode::ReturnVoid).v0id();
97 }
98 }
99 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
100 auto graph = CreateEmptyGraph();
101 GRAPH(graph)
102 {
103 CONSTANT(10, 0);
104 BASIC_BLOCK(2, 1)
105 {
106 INST(0, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
107 INST(1, Opcode::IsMustDeoptimize).b();
108 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
109
110 INST(3, Opcode::NOP);
111 INST(4, Opcode::NOP);
112 INST(5, Opcode::NOP);
113
114 INST(9, Opcode::ReturnVoid).v0id();
115 }
116 }
117 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
118 }
119
TEST_F(DeoptimizeEliminationTest,ChaGuardOneBlockCallTest)120 TEST_F(DeoptimizeEliminationTest, ChaGuardOneBlockCallTest)
121 {
122 // Not applied. Call to runtime between guards.
123 GRAPH(GetGraph())
124 {
125 CONSTANT(10, 0);
126 BASIC_BLOCK(2, 1)
127 {
128 INST(0, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
129 INST(1, Opcode::IsMustDeoptimize).b();
130 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
131 INST(20, Opcode::SaveState).NoVregs();
132 INST(6, Opcode::CallStatic).v0id().InputsAutoType(20);
133
134 INST(3, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
135 INST(4, Opcode::IsMustDeoptimize).b();
136 INST(5, Opcode::DeoptimizeIf).Inputs(4, 3);
137
138 INST(9, Opcode::ReturnVoid).v0id();
139 }
140 }
141 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
142 ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
143 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
144 }
145
TEST_F(DeoptimizeEliminationTest,ChaGuardOneBlockSeveralGuardsTest)146 TEST_F(DeoptimizeEliminationTest, ChaGuardOneBlockSeveralGuardsTest)
147 {
148 GRAPH(GetGraph())
149 {
150 CONSTANT(10, 0);
151 BASIC_BLOCK(2, 1)
152 {
153 INST(0, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
154 INST(1, Opcode::IsMustDeoptimize).b();
155 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
156 INST(20, Opcode::SaveState).NoVregs();
157 INST(6, Opcode::CallStatic).v0id().InputsAutoType(20);
158
159 INST(3, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
160 INST(4, Opcode::IsMustDeoptimize).b();
161 INST(5, Opcode::DeoptimizeIf).Inputs(4, 3);
162
163 INST(11, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
164 INST(12, Opcode::IsMustDeoptimize).b();
165 INST(13, Opcode::DeoptimizeIf).Inputs(12, 11);
166
167 INST(9, Opcode::ReturnVoid).v0id();
168 }
169 }
170 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
171 auto graph = CreateEmptyGraph();
172 GRAPH(graph)
173 {
174 CONSTANT(10, 0);
175 BASIC_BLOCK(2, 1)
176 {
177 INST(0, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
178 INST(1, Opcode::IsMustDeoptimize).b();
179 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
180 INST(20, Opcode::SaveState).NoVregs();
181 INST(6, Opcode::CallStatic).v0id().InputsAutoType(20);
182
183 INST(3, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
184 INST(4, Opcode::IsMustDeoptimize).b();
185 INST(5, Opcode::DeoptimizeIf).Inputs(4, 3);
186
187 INST(11, Opcode::NOP);
188 INST(12, Opcode::NOP);
189 INST(13, Opcode::NOP);
190
191 INST(9, Opcode::ReturnVoid).v0id();
192 }
193 }
194 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
195 }
196
TEST_F(DeoptimizeEliminationTest,ChaGuardOneBlockCallInlinedTest)197 TEST_F(DeoptimizeEliminationTest, ChaGuardOneBlockCallInlinedTest)
198 {
199 GRAPH(GetGraph())
200 {
201 CONSTANT(10, 0);
202 BASIC_BLOCK(2, 1)
203 {
204 INST(0, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
205 INST(1, Opcode::IsMustDeoptimize).b();
206 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
207 INST(20, Opcode::SaveState).NoVregs();
208 INST(6, Opcode::CallStatic).v0id().Inlined().InputsAutoType(20);
209 INST(7, Opcode::ReturnInlined).Inputs(0);
210
211 INST(3, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
212 INST(4, Opcode::IsMustDeoptimize).b();
213 INST(5, Opcode::DeoptimizeIf).Inputs(4, 3);
214
215 INST(9, Opcode::ReturnVoid).v0id();
216 }
217 }
218 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
219 auto graph = CreateEmptyGraph();
220 GRAPH(graph)
221 {
222 CONSTANT(10, 0);
223 BASIC_BLOCK(2, 1)
224 {
225 INST(0, Opcode::SaveStateDeoptimize).Inputs(10).SrcVregs({10});
226 INST(1, Opcode::IsMustDeoptimize).b();
227 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
228 INST(20, Opcode::SaveState).NoVregs();
229 INST(6, Opcode::CallStatic).v0id().Inlined().InputsAutoType(20);
230 INST(7, Opcode::ReturnInlined).Inputs(0);
231
232 INST(3, Opcode::NOP);
233 INST(4, Opcode::NOP);
234 INST(5, Opcode::NOP);
235
236 INST(9, Opcode::ReturnVoid).v0id();
237 }
238 }
239 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
240 }
241
TEST_F(DeoptimizeEliminationTest,ChaGuardIfTest)242 TEST_F(DeoptimizeEliminationTest, ChaGuardIfTest)
243 {
244 /*
245 * Not applied.
246 * bb1
247 * guard
248 * | \
249 * | bb2
250 * | runtime call
251 * | /
252 * bb3
253 * guard
254 */
255 GRAPH(GetGraph())
256 {
257 PARAMETER(10, 0).s32();
258 CONSTANT(11, 1);
259 BASIC_BLOCK(2, 4, 5)
260 {
261 INST(0, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
262 INST(1, Opcode::IsMustDeoptimize).b();
263 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
264 INST(3, Opcode::Compare).b().CC(CC_LT).Inputs(10, 11);
265 INST(4, Opcode::IfImm).CC(CC_NE).Inputs(3).Imm(0);
266 }
267 BASIC_BLOCK(4, 5)
268 {
269 INST(20, Opcode::SaveState).NoVregs();
270 INST(5, Opcode::CallStatic).v0id().InputsAutoType(20);
271 }
272 BASIC_BLOCK(5, 1)
273 {
274 INST(6, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
275 INST(7, Opcode::IsMustDeoptimize).b();
276 INST(8, Opcode::DeoptimizeIf).Inputs(7, 6);
277 INST(9, Opcode::ReturnVoid).v0id();
278 }
279 }
280 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
281 ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
282 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
283 }
284
TEST_F(DeoptimizeEliminationTest,ChaGuardIfSeveralGuardsTest)285 TEST_F(DeoptimizeEliminationTest, ChaGuardIfSeveralGuardsTest)
286 {
287 /*
288 * bb1
289 * guard
290 * call
291 * guard
292 * | \
293 * | bb2
294 * | some inst
295 * | /
296 * bb3
297 * guard
298 */
299 GRAPH(GetGraph())
300 {
301 PARAMETER(10, 0).s32();
302 CONSTANT(11, 1);
303 BASIC_BLOCK(2, 4, 5)
304 {
305 INST(0, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
306 INST(1, Opcode::IsMustDeoptimize).b();
307 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
308 INST(20, Opcode::SaveState).NoVregs();
309 INST(12, Opcode::CallStatic).v0id().InputsAutoType(20);
310 INST(13, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
311 INST(14, Opcode::IsMustDeoptimize).b();
312 INST(15, Opcode::DeoptimizeIf).Inputs(14, 13);
313 INST(3, Opcode::Compare).b().CC(CC_LT).Inputs(10, 11);
314 INST(4, Opcode::IfImm).CC(CC_NE).Inputs(3).Imm(0);
315 }
316 BASIC_BLOCK(4, 5)
317 {
318 INST(21, Opcode::SaveState).NoVregs();
319 INST(5, Opcode::CallStatic).v0id().Inlined().InputsAutoType(21);
320 INST(16, Opcode::ReturnInlined).Inputs(0);
321 }
322 BASIC_BLOCK(5, 1)
323 {
324 INST(6, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
325 INST(7, Opcode::IsMustDeoptimize).b();
326 INST(8, Opcode::DeoptimizeIf).Inputs(7, 6);
327 INST(9, Opcode::ReturnVoid).v0id();
328 }
329 }
330 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
331 auto graph = CreateEmptyGraph();
332 GRAPH(graph)
333 {
334 PARAMETER(10, 0).s32();
335 CONSTANT(11, 1);
336 BASIC_BLOCK(2, 4, 5)
337 {
338 INST(0, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
339 INST(1, Opcode::IsMustDeoptimize).b();
340 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
341 INST(20, Opcode::SaveState).NoVregs();
342 INST(12, Opcode::CallStatic).v0id().InputsAutoType(20);
343 INST(13, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
344 INST(14, Opcode::IsMustDeoptimize).b();
345 INST(15, Opcode::DeoptimizeIf).Inputs(14, 13);
346 INST(3, Opcode::Compare).b().CC(CC_LT).Inputs(10, 11);
347 INST(4, Opcode::IfImm).CC(CC_NE).Inputs(3).Imm(0);
348 }
349 BASIC_BLOCK(4, 5)
350 {
351 INST(21, Opcode::SaveState).NoVregs();
352 INST(5, Opcode::CallStatic).v0id().Inlined().InputsAutoType(21);
353 INST(16, Opcode::ReturnInlined).Inputs(0);
354 }
355 BASIC_BLOCK(5, 1)
356 {
357 INST(6, Opcode::NOP);
358 INST(7, Opcode::NOP);
359 INST(8, Opcode::NOP);
360 INST(9, Opcode::ReturnVoid).v0id();
361 }
362 }
363 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
364 }
365
TEST_F(DeoptimizeEliminationTest,ChaGuardLoopTest)366 TEST_F(DeoptimizeEliminationTest, ChaGuardLoopTest)
367 {
368 GRAPH(GetGraph())
369 {
370 CONSTANT(10, 0);
371 CONSTANT(11, 1);
372 CONSTANT(12, 10);
373 BASIC_BLOCK(2, 3)
374 {
375 INST(0, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
376 INST(1, Opcode::IsMustDeoptimize).b();
377 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
378 }
379 BASIC_BLOCK(3, 4, 5)
380 {
381 INST(3, Opcode::Phi).s32().Inputs(10, 7);
382 INST(8, Opcode::Compare).b().CC(CC_LT).Inputs(3, 12);
383 INST(9, Opcode::IfImm).CC(CC_NE).Inputs(8).Imm(0);
384 }
385 BASIC_BLOCK(4, 3)
386 {
387 INST(4, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
388 INST(5, Opcode::IsMustDeoptimize).b();
389 INST(6, Opcode::DeoptimizeIf).Inputs(5, 4);
390 INST(7, Opcode::Add).s32().Inputs(3, 11);
391 }
392 BASIC_BLOCK(5, 1)
393 {
394 INST(13, Opcode::Return).s32().Inputs(3);
395 }
396 }
397 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
398 auto graph = CreateEmptyGraph();
399 GRAPH(graph)
400 {
401 CONSTANT(10, 0);
402 CONSTANT(11, 1);
403 CONSTANT(12, 10);
404 BASIC_BLOCK(2, 3)
405 {
406 INST(0, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
407 INST(1, Opcode::IsMustDeoptimize).b();
408 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
409 }
410 BASIC_BLOCK(3, 4, 5)
411 {
412 INST(3, Opcode::Phi).s32().Inputs(10, 7);
413 INST(8, Opcode::Compare).b().CC(CC_LT).Inputs(3, 12);
414 INST(9, Opcode::IfImm).CC(CC_NE).Inputs(8).Imm(0);
415 }
416 BASIC_BLOCK(4, 3)
417 {
418 INST(4, Opcode::NOP);
419 INST(5, Opcode::NOP);
420 INST(6, Opcode::NOP);
421 INST(7, Opcode::Add).s32().Inputs(3, 11);
422 }
423 BASIC_BLOCK(5, 1)
424 {
425 INST(13, Opcode::Return).s32().Inputs(3);
426 }
427 }
428 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
429 }
430
TEST_F(DeoptimizeEliminationTest,ChaGuardLoopWithCallAfterGuardTest)431 TEST_F(DeoptimizeEliminationTest, ChaGuardLoopWithCallAfterGuardTest)
432 {
433 GRAPH(GetGraph())
434 {
435 CONSTANT(10, 0);
436 CONSTANT(11, 1);
437 CONSTANT(12, 10);
438 BASIC_BLOCK(2, 3)
439 {
440 INST(0, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
441 INST(1, Opcode::IsMustDeoptimize).b();
442 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
443 }
444 BASIC_BLOCK(3, 4, 5)
445 {
446 INST(3, Opcode::Phi).s32().Inputs(10, 7);
447 INST(8, Opcode::Compare).b().CC(CC_LT).Inputs(3, 12);
448 INST(9, Opcode::IfImm).CC(CC_NE).Inputs(8).Imm(0);
449 }
450 BASIC_BLOCK(4, 3)
451 {
452 INST(4, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
453 INST(5, Opcode::IsMustDeoptimize).b();
454 INST(6, Opcode::DeoptimizeIf).Inputs(5, 4);
455 INST(20, Opcode::SaveState).NoVregs();
456 INST(14, Opcode::CallStatic).v0id().InputsAutoType(20);
457 INST(7, Opcode::Add).s32().Inputs(3, 11);
458 }
459 BASIC_BLOCK(5, 1)
460 {
461 INST(13, Opcode::Return).s32().Inputs(3);
462 }
463 }
464 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
465 ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
466 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
467 }
468
TEST_F(DeoptimizeEliminationTest,ChaGuardLoopWithCallBeforeGuardTest)469 TEST_F(DeoptimizeEliminationTest, ChaGuardLoopWithCallBeforeGuardTest)
470 {
471 GRAPH(GetGraph())
472 {
473 CONSTANT(10, 0);
474 CONSTANT(11, 1);
475 CONSTANT(12, 10);
476 BASIC_BLOCK(2, 3)
477 {
478 INST(0, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
479 INST(1, Opcode::IsMustDeoptimize).b();
480 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
481 }
482 BASIC_BLOCK(3, 4, 5)
483 {
484 INST(3, Opcode::Phi).s32().Inputs(10, 7);
485 INST(8, Opcode::Compare).b().CC(CC_LT).Inputs(3, 12);
486 INST(9, Opcode::IfImm).CC(CC_NE).Inputs(8).Imm(0);
487 }
488 BASIC_BLOCK(4, 3)
489 {
490 INST(20, Opcode::SaveState).NoVregs();
491 INST(14, Opcode::CallStatic).v0id().InputsAutoType(20);
492 INST(4, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
493 INST(5, Opcode::IsMustDeoptimize).b();
494 INST(6, Opcode::DeoptimizeIf).Inputs(5, 4);
495 INST(7, Opcode::Add).s32().Inputs(3, 11);
496 }
497 BASIC_BLOCK(5, 1)
498 {
499 INST(13, Opcode::Return).s32().Inputs(3);
500 }
501 }
502 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
503 ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
504 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
505 }
506
TEST_F(DeoptimizeEliminationTest,ChaGuardLoopWithCallBetweenGuardsWithDomGuardTest)507 TEST_F(DeoptimizeEliminationTest, ChaGuardLoopWithCallBetweenGuardsWithDomGuardTest)
508 {
509 GRAPH(GetGraph())
510 {
511 CONSTANT(10, 0);
512 CONSTANT(11, 1);
513 CONSTANT(12, 10);
514 BASIC_BLOCK(2, 3)
515 {
516 INST(0, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
517 INST(1, Opcode::IsMustDeoptimize).b();
518 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
519 }
520 BASIC_BLOCK(3, 4, 5)
521 {
522 INST(3, Opcode::Phi).s32().Inputs(10, 7);
523 INST(8, Opcode::Compare).b().CC(CC_LT).Inputs(3, 12);
524 INST(9, Opcode::IfImm).CC(CC_NE).Inputs(8).Imm(0);
525 }
526 BASIC_BLOCK(4, 3)
527 {
528 INST(15, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
529 INST(16, Opcode::IsMustDeoptimize).b();
530 INST(17, Opcode::DeoptimizeIf).Inputs(16, 15);
531 INST(20, Opcode::SaveState).NoVregs();
532 INST(14, Opcode::CallStatic).v0id().InputsAutoType(20);
533 INST(4, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
534 INST(5, Opcode::IsMustDeoptimize).b();
535 INST(6, Opcode::DeoptimizeIf).Inputs(5, 4);
536 INST(7, Opcode::Add).s32().Inputs(3, 11);
537 }
538 BASIC_BLOCK(5, 1)
539 {
540 INST(13, Opcode::Return).s32().Inputs(3);
541 }
542 }
543 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
544 auto graph = CreateEmptyGraph();
545 GRAPH(graph)
546 {
547 CONSTANT(10, 0);
548 CONSTANT(11, 1);
549 CONSTANT(12, 10);
550 BASIC_BLOCK(2, 3)
551 {
552 INST(0, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
553 INST(1, Opcode::IsMustDeoptimize).b();
554 INST(2, Opcode::DeoptimizeIf).Inputs(1, 0);
555 }
556 BASIC_BLOCK(3, 4, 5)
557 {
558 INST(3, Opcode::Phi).s32().Inputs(10, 7);
559 INST(8, Opcode::Compare).b().CC(CC_LT).Inputs(3, 12);
560 INST(9, Opcode::IfImm).CC(CC_NE).Inputs(8).Imm(0);
561 }
562 BASIC_BLOCK(4, 3)
563 {
564 INST(15, Opcode::NOP);
565 INST(16, Opcode::NOP);
566 INST(17, Opcode::NOP);
567 INST(20, Opcode::SaveState).NoVregs();
568 INST(14, Opcode::CallStatic).v0id().InputsAutoType(20);
569 INST(4, Opcode::SaveStateDeoptimize).Inputs(10, 11).SrcVregs({0, 1});
570 INST(5, Opcode::IsMustDeoptimize).b();
571 INST(6, Opcode::DeoptimizeIf).Inputs(5, 4);
572 INST(7, Opcode::Add).s32().Inputs(3, 11);
573 }
574 BASIC_BLOCK(5, 1)
575 {
576 INST(13, Opcode::Return).s32().Inputs(3);
577 }
578 }
579 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
580 }
581
TEST_F(DeoptimizeEliminationTest,ChaGuardLoopWithDuplicatedGuardsTest)582 TEST_F(DeoptimizeEliminationTest, ChaGuardLoopWithDuplicatedGuardsTest)
583 {
584 GRAPH(GetGraph())
585 {
586 CONSTANT(0, 0);
587 CONSTANT(1, 1);
588 PARAMETER(2, 0).s32();
589 BASIC_BLOCK(2, 3, 10)
590 {
591 INST(3, Opcode::Compare).b().CC(CC_LT).Inputs(0, 2);
592 INST(4, Opcode::IfImm).CC(CC_NE).Inputs(3).Imm(0);
593 }
594 BASIC_BLOCK(3, 4, 5)
595 {
596 INST(19, Opcode::Phi).s32().Inputs(0, 14);
597 INST(5, Opcode::SaveStateDeoptimize).Inputs(0, 1, 2).SrcVregs({0, 1, 2});
598 INST(6, Opcode::IsMustDeoptimize).b();
599 INST(7, Opcode::DeoptimizeIf).Inputs(6, 5);
600 INST(8, Opcode::Compare).b().CC(CC_LT).Inputs(0, 2);
601 INST(9, Opcode::IfImm).CC(CC_NE).Inputs(8).Imm(0);
602 }
603 BASIC_BLOCK(4, 5)
604 {
605 INST(10, Opcode::SaveStateDeoptimize).Inputs(0, 1, 2).SrcVregs({0, 1, 2});
606 INST(11, Opcode::IsMustDeoptimize).b();
607 INST(12, Opcode::DeoptimizeIf).Inputs(11, 10);
608 }
609 BASIC_BLOCK(5, 3, 10)
610 {
611 INST(20, Opcode::SaveState).NoVregs();
612 INST(13, Opcode::CallStatic).v0id().InputsAutoType(20);
613 INST(14, Opcode::Add).s32().Inputs(19, 1);
614 INST(15, Opcode::Compare).b().CC(CC_LT).Inputs(14, 2);
615 INST(16, Opcode::IfImm).CC(CC_NE).Inputs(15).Imm(0);
616 }
617
618 BASIC_BLOCK(10, 1)
619 {
620 INST(17, Opcode::Phi).s32().Inputs(0, 14);
621 INST(18, Opcode::Return).s32().Inputs(17);
622 }
623 }
624 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
625 auto graph = CreateEmptyGraph();
626 GRAPH(graph)
627 {
628 CONSTANT(0, 0);
629 CONSTANT(1, 1);
630 PARAMETER(2, 0).s32();
631 BASIC_BLOCK(2, 3, 10)
632 {
633 INST(3, Opcode::Compare).b().CC(CC_LT).Inputs(0, 2);
634 INST(4, Opcode::IfImm).CC(CC_NE).Inputs(3).Imm(0);
635 }
636 BASIC_BLOCK(3, 4, 5)
637 {
638 INST(19, Opcode::Phi).s32().Inputs(0, 14);
639 INST(5, Opcode::SaveStateDeoptimize).Inputs(0, 1, 2).SrcVregs({0, 1, 2});
640 INST(6, Opcode::IsMustDeoptimize).b();
641 INST(7, Opcode::DeoptimizeIf).Inputs(6, 5);
642 INST(8, Opcode::Compare).b().CC(CC_LT).Inputs(0, 2);
643 INST(9, Opcode::IfImm).CC(CC_NE).Inputs(8).Imm(0);
644 }
645 BASIC_BLOCK(4, 5)
646 {
647 INST(10, Opcode::NOP);
648 INST(11, Opcode::NOP);
649 INST(12, Opcode::NOP);
650 }
651 BASIC_BLOCK(5, 3, 10)
652 {
653 INST(20, Opcode::SaveState).NoVregs();
654 INST(13, Opcode::CallStatic).v0id().InputsAutoType(20);
655 INST(14, Opcode::Add).s32().Inputs(19, 1);
656 INST(15, Opcode::Compare).b().CC(CC_LT).Inputs(14, 2);
657 INST(16, Opcode::IfImm).CC(CC_NE).Inputs(15).Imm(0);
658 }
659
660 BASIC_BLOCK(10, 1)
661 {
662 INST(17, Opcode::Phi).s32().Inputs(0, 14);
663 INST(18, Opcode::Return).s32().Inputs(17);
664 }
665 }
666 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
667 }
668
TEST_F(DeoptimizeEliminationTest,ChaGuardNotDominateTest)669 TEST_F(DeoptimizeEliminationTest, ChaGuardNotDominateTest)
670 {
671 GRAPH(GetGraph())
672 {
673 PARAMETER(0, 0).s32();
674 PARAMETER(1, 1).s32();
675 BASIC_BLOCK(2, 3, 4)
676 {
677 INST(2, Opcode::Compare).b().CC(CC_EQ).Inputs(0, 1);
678 INST(3, Opcode::IfImm).CC(CC_NE).Inputs(2).Imm(0);
679 }
680 BASIC_BLOCK(3, 4)
681 {
682 INST(4, Opcode::SaveStateDeoptimize).Inputs(0, 1).SrcVregs({0, 1});
683 INST(5, Opcode::IsMustDeoptimize).b();
684 INST(6, Opcode::DeoptimizeIf).Inputs(5, 4);
685 }
686 BASIC_BLOCK(4, 1)
687 {
688 INST(7, Opcode::SaveStateDeoptimize).Inputs(0, 1).SrcVregs({0, 1});
689 INST(8, Opcode::IsMustDeoptimize).b();
690 INST(9, Opcode::DeoptimizeIf).Inputs(8, 7);
691 INST(10, Opcode::ReturnVoid).v0id();
692 }
693 }
694 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
695 ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
696 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
697 }
698
TEST_F(DeoptimizeEliminationTest,ChaGuardIfWithGuardsTest)699 TEST_F(DeoptimizeEliminationTest, ChaGuardIfWithGuardsTest)
700 {
701 /*
702 * some code
703 * / \
704 * call call
705 * guard guard
706 * \ /
707 * \ /
708 * guard(*, deleted)
709 */
710 GRAPH(GetGraph())
711 {
712 PARAMETER(0, 0).s32();
713 PARAMETER(1, 1).s32();
714 BASIC_BLOCK(2, 3, 4)
715 {
716 INST(5, Opcode::Compare).b().CC(CC_EQ).Inputs(0, 1);
717 INST(6, Opcode::IfImm).CC(CC_NE).Inputs(5).Imm(0);
718 }
719 BASIC_BLOCK(3, 5)
720 {
721 INST(20, Opcode::SaveState).NoVregs();
722 INST(7, Opcode::CallStatic).v0id().InputsAutoType(20);
723 INST(8, Opcode::SaveStateDeoptimize).Inputs(0, 1).SrcVregs({0, 1});
724 INST(9, Opcode::IsMustDeoptimize).b();
725 INST(10, Opcode::DeoptimizeIf).Inputs(9, 8);
726 }
727 BASIC_BLOCK(4, 5)
728 {
729 INST(21, Opcode::SaveState).NoVregs();
730 INST(11, Opcode::CallStatic).v0id().InputsAutoType(21);
731 INST(12, Opcode::SaveStateDeoptimize).Inputs(0, 1).SrcVregs({0, 1});
732 INST(13, Opcode::IsMustDeoptimize).b();
733 INST(14, Opcode::DeoptimizeIf).Inputs(13, 12);
734 }
735 BASIC_BLOCK(5, 1)
736 {
737 INST(15, Opcode::SaveStateDeoptimize).Inputs(0, 1).SrcVregs({0, 1});
738 INST(16, Opcode::IsMustDeoptimize).b();
739 INST(17, Opcode::DeoptimizeIf).Inputs(16, 15);
740 INST(18, Opcode::ReturnVoid).v0id();
741 }
742 }
743 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
744 auto graph = CreateEmptyGraph();
745 GRAPH(graph)
746 {
747 PARAMETER(0, 0).s32();
748 PARAMETER(1, 1).s32();
749 BASIC_BLOCK(2, 3, 4)
750 {
751 INST(5, Opcode::Compare).b().CC(CC_EQ).Inputs(0, 1);
752 INST(6, Opcode::IfImm).CC(CC_NE).Inputs(5).Imm(0);
753 }
754 BASIC_BLOCK(3, 5)
755 {
756 INST(20, Opcode::SaveState).NoVregs();
757 INST(7, Opcode::CallStatic).v0id().InputsAutoType(20);
758 INST(8, Opcode::SaveStateDeoptimize).Inputs(0, 1).SrcVregs({0, 1});
759 INST(9, Opcode::IsMustDeoptimize).b();
760 INST(10, Opcode::DeoptimizeIf).Inputs(9, 8);
761 }
762 BASIC_BLOCK(4, 5)
763 {
764 INST(21, Opcode::SaveState).NoVregs();
765 INST(11, Opcode::CallStatic).v0id().InputsAutoType(21);
766 INST(12, Opcode::SaveStateDeoptimize).Inputs(0, 1).SrcVregs({0, 1});
767 INST(13, Opcode::IsMustDeoptimize).b();
768 INST(14, Opcode::DeoptimizeIf).Inputs(13, 12);
769 }
770 BASIC_BLOCK(5, 1)
771 {
772 INST(15, Opcode::NOP);
773 INST(16, Opcode::NOP);
774 INST(17, Opcode::NOP);
775 INST(18, Opcode::ReturnVoid).v0id();
776 }
777 }
778 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
779 }
780
TEST_F(DeoptimizeEliminationTest,ReplaceByDeoptimizeTest)781 TEST_F(DeoptimizeEliminationTest, ReplaceByDeoptimizeTest)
782 {
783 GRAPH(GetGraph())
784 {
785 CONSTANT(0, 1);
786 BASIC_BLOCK(2, 1)
787 {
788 INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});
789 INST(3, Opcode::DeoptimizeIf).Inputs(0, 2);
790 INST(4, Opcode::ReturnVoid).v0id();
791 }
792 }
793 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
794 auto graph = CreateEmptyGraph();
795 GRAPH(graph)
796 {
797 CONSTANT(0, 1);
798 BASIC_BLOCK(2, 1)
799 {
800 INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});
801 INST(3, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::INVALID).Inputs(2);
802 }
803 }
804 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
805 }
806
TEST_F(DeoptimizeEliminationTest,ReplaceByDeoptimizeInliningTest)807 TEST_F(DeoptimizeEliminationTest, ReplaceByDeoptimizeInliningTest)
808 {
809 GRAPH(GetGraph())
810 {
811 CONSTANT(0, 1);
812 BASIC_BLOCK(2, 1)
813 {
814 INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});
815 INST(3, Opcode::CallStatic).v0id().InputsAutoType(2).Inlined();
816 INST(4, Opcode::SaveState).Inputs(0).SrcVregs({0});
817 INST(7, Opcode::DeoptimizeIf).Inputs(0, 4);
818 INST(5, Opcode::ReturnInlined).Inputs(2);
819 INST(6, Opcode::ReturnVoid).v0id();
820 }
821 }
822 INS(4).CastToSaveState()->SetCallerInst(static_cast<CallInst *>(&INS(3)));
823 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
824 auto graph = CreateEmptyGraph();
825 GRAPH(graph)
826 {
827 CONSTANT(0, 1);
828 BASIC_BLOCK(2, 1)
829 {
830 INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});
831 INST(3, Opcode::CallStatic).v0id().InputsAutoType(2).Inlined();
832 INST(4, Opcode::SaveState).Inputs(0).SrcVregs({0});
833 INST(5, Opcode::ReturnInlined).Inputs(2);
834 INST(8, Opcode::Deoptimize).Inputs(4);
835 }
836 }
837 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
838 }
839
TEST_F(DeoptimizeEliminationTest,RemoveSafePoint)840 TEST_F(DeoptimizeEliminationTest, RemoveSafePoint)
841 {
842 GRAPH(GetGraph())
843 {
844 PARAMETER(0, 0).s32();
845 PARAMETER(1, 1).s32();
846 INST(2, Opcode::SafePoint).Inputs(0, 1).SrcVregs({0, 1});
847 BASIC_BLOCK(2, 1)
848 {
849 INST(3, Opcode::Add).s32().Inputs(0, 1);
850 INST(4, Opcode::Return).s32().Inputs(3);
851 }
852 }
853 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
854 GetGraph()->RunPass<Cleanup>();
855 auto graph = CreateEmptyGraph();
856 GRAPH(graph)
857 {
858 PARAMETER(0, 0).s32();
859 PARAMETER(1, 1).s32();
860 BASIC_BLOCK(2, 1)
861 {
862 INST(3, Opcode::Add).s32().Inputs(0, 1);
863 INST(4, Opcode::Return).s32().Inputs(3);
864 }
865 }
866 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
867 }
868
869 // Not applied, have runtime calls
TEST_F(DeoptimizeEliminationTest,RemoveSafePoint1)870 TEST_F(DeoptimizeEliminationTest, RemoveSafePoint1)
871 {
872 GRAPH(GetGraph())
873 {
874 PARAMETER(0, 0).s32();
875 PARAMETER(1, 1).s32();
876 INST(2, Opcode::SafePoint).Inputs(0, 1).SrcVregs({0, 1});
877 BASIC_BLOCK(2, 1)
878 {
879 INST(20, Opcode::SaveState).NoVregs();
880 INST(5, Opcode::CallStatic).v0id().InputsAutoType(20);
881 INST(3, Opcode::Add).s32().Inputs(0, 1);
882 INST(4, Opcode::Return).s32().Inputs(3);
883 }
884 }
885 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
886 ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
887 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
888 }
889
890 // Not applied, a lot of instructions
TEST_F(DeoptimizeEliminationTest,RemoveSafePoint2)891 TEST_F(DeoptimizeEliminationTest, RemoveSafePoint2)
892 {
893 uint64_t N = options.GetCompilerSafepointEliminationLimit();
894 auto block = GetGraph()->CreateEmptyBlock();
895 GetGraph()->GetStartBlock()->AddSucc(block);
896 block->AddSucc(GetGraph()->GetEndBlock());
897 auto param1 = GetGraph()->CreateInstParameter(0);
898 auto param2 = GetGraph()->CreateInstParameter(1);
899 param1->SetType(DataType::INT32);
900 param2->SetType(DataType::INT32);
901 GetGraph()->GetStartBlock()->AppendInst(param1);
902 GetGraph()->GetStartBlock()->AppendInst(param2);
903 auto sp = GetGraph()->CreateInstSafePoint();
904 sp->AppendInput(param1);
905 sp->AppendInput(param2);
906 sp->SetVirtualRegister(0, VirtualRegister(0, false));
907 sp->SetVirtualRegister(1, VirtualRegister(1, false));
908 GetGraph()->GetStartBlock()->AppendInst(sp);
909 ArenaVector<Inst *> insts(GetGraph()->GetLocalAllocator()->Adapter());
910 insts.push_back(param1);
911 insts.push_back(param2);
912 for (uint64_t i = 2; i <= N + 1; i++) {
913 auto inst = GetGraph()->CreateInstAdd();
914 inst->SetType(DataType::INT32);
915 inst->SetInput(0, insts[i - 2]);
916 inst->SetInput(1, insts[i - 1]);
917 block->AppendInst(inst);
918 insts.push_back(inst);
919 }
920 auto ret = GetGraph()->CreateInstReturn();
921 ret->SetType(DataType::INT32);
922 ret->SetInput(0, insts[N + 1]);
923 block->AppendInst(ret);
924 GraphChecker(GetGraph()).Check();
925 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
926 ASSERT_FALSE(GetGraph()->RunPass<DeoptimizeElimination>());
927 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
928 }
929
930 // Applied, have CallStatic.Inlined
TEST_F(DeoptimizeEliminationTest,RemoveSafePoint3)931 TEST_F(DeoptimizeEliminationTest, RemoveSafePoint3)
932 {
933 GRAPH(GetGraph())
934 {
935 PARAMETER(0, 0).s32();
936 PARAMETER(1, 1).s32();
937 INST(2, Opcode::SafePoint).Inputs(0, 1).SrcVregs({0, 1});
938 BASIC_BLOCK(2, 1)
939 {
940 INST(8, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});
941 INST(5, Opcode::CallStatic).v0id().InputsAutoType(8).Inlined();
942 INST(3, Opcode::Add).s32().Inputs(0, 1);
943 INST(7, Opcode::ReturnInlined).Inputs(8);
944 INST(4, Opcode::Return).s32().Inputs(3);
945 }
946 }
947 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
948 GetGraph()->RunPass<Cleanup>();
949 auto graph = CreateEmptyGraph();
950 GRAPH(graph)
951 {
952 PARAMETER(0, 0).s32();
953 PARAMETER(1, 1).s32();
954 BASIC_BLOCK(2, 1)
955 {
956 INST(8, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});
957 INST(5, Opcode::CallStatic).v0id().InputsAutoType(8).Inlined();
958 INST(3, Opcode::Add).s32().Inputs(0, 1);
959 INST(7, Opcode::ReturnInlined).Inputs(8);
960 INST(4, Opcode::Return).s32().Inputs(3);
961 }
962 }
963 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
964 }
965
966 // Removes numeric inputs from SS without Deoptimize and doen't remove with Deoptimize
TEST_F(DeoptimizeEliminationTest,RemovNumericInputs)967 TEST_F(DeoptimizeEliminationTest, RemovNumericInputs)
968 {
969 GRAPH(GetGraph())
970 {
971 PARAMETER(0, 1).b();
972 PARAMETER(1, 2).s32();
973 PARAMETER(2, 3).f64();
974 PARAMETER(3, 4).ref();
975 BASIC_BLOCK(2, -1)
976 {
977 INST(4, Opcode::SaveState).Inputs(0, 1, 2, 3).SrcVregs({0, 1, 2, 3});
978 INST(8, Opcode::DeoptimizeIf).Inputs(0, 4);
979 INST(5, Opcode::SaveState).Inputs(0, 1, 2, 3).SrcVregs({0, 1, 2, 3});
980 INST(6, Opcode::CallStatic).u64().InputsAutoType(0, 1, 2, 3, 5);
981 INST(7, Opcode::Return).u64().Inputs(6);
982 }
983 }
984 Graph *graph_et = CreateEmptyGraph();
985 GRAPH(graph_et)
986 {
987 PARAMETER(0, 1).b();
988 PARAMETER(1, 2).s32();
989 PARAMETER(2, 3).f64();
990 PARAMETER(3, 4).ref();
991 BASIC_BLOCK(2, -1)
992 {
993 INST(4, Opcode::SaveState).Inputs(0, 1, 2, 3).SrcVregs({0, 1, 2, 3});
994 INST(8, Opcode::DeoptimizeIf).Inputs(0, 4);
995 INST(5, Opcode::SaveState).Inputs(3).SrcVregs({3});
996 INST(6, Opcode::CallStatic).u64().InputsAutoType(0, 1, 2, 3, 5);
997 INST(7, Opcode::Return).u64().Inputs(6);
998 }
999 }
1000
1001 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
1002 GraphChecker(GetGraph()).Check();
1003 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph_et));
1004 }
1005
1006 // Removes object inputs from SS without Deoptimize
TEST_F(DeoptimizeEliminationTest,RemovObjectInputs)1007 TEST_F(DeoptimizeEliminationTest, RemovObjectInputs)
1008 {
1009 // 1 don't removed because they used in SS with deoptimization
1010 GRAPH(GetGraph())
1011 {
1012 PARAMETER(0, 1).b();
1013 PARAMETER(1, 2).ref();
1014 PARAMETER(2, 3).ref();
1015 PARAMETER(3, 4).ref();
1016 BASIC_BLOCK(2, -1)
1017 {
1018 INST(4, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});
1019 INST(8, Opcode::DeoptimizeIf).Inputs(0, 4);
1020 INST(5, Opcode::SaveState).Inputs(0, 1, 2, 3).SrcVregs({0, 1, 2, 3});
1021 INST(6, Opcode::CallStatic).u64().InputsAutoType(0, 5);
1022 INST(7, Opcode::Return).u64().Inputs(6);
1023 }
1024 }
1025 Graph *graph_et = CreateEmptyGraph();
1026 GRAPH(graph_et)
1027 {
1028 PARAMETER(0, 1).b();
1029 PARAMETER(1, 2).ref();
1030 PARAMETER(2, 3).ref();
1031 PARAMETER(3, 4).ref();
1032 BASIC_BLOCK(2, -1)
1033 {
1034 INST(4, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});
1035 INST(8, Opcode::DeoptimizeIf).Inputs(0, 4);
1036 INST(5, Opcode::SaveState).Inputs(1).SrcVregs({1});
1037 INST(6, Opcode::CallStatic).u64().InputsAutoType(0, 5);
1038 INST(7, Opcode::Return).u64().Inputs(6);
1039 }
1040 }
1041
1042 ASSERT_TRUE(GetGraph()->RunPass<DeoptimizeElimination>());
1043 GraphChecker(GetGraph()).Check();
1044 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph_et));
1045 }
1046 } // namespace panda::compiler
1047