1 /*
2 * Copyright (c) 2021-2023 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
18 #include "optimizer/optimizations/scheduler.h"
19
20 namespace panda::compiler {
21 class SchedulerTest : public GraphTest {};
22
23 // NOLINTBEGIN(readability-magic-numbers)
TEST_F(SchedulerTest,Basic)24 TEST_F(SchedulerTest, Basic)
25 {
26 GRAPH(GetGraph())
27 {
28 CONSTANT(0U, 42U);
29 CONSTANT(1U, 43U);
30 CONSTANT(2U, 44U);
31 CONSTANT(3U, 45U);
32 CONSTANT(4U, 46U);
33 CONSTANT(5U, 47U);
34 CONSTANT(6U, 48U);
35 CONSTANT(7U, 49U);
36
37 BASIC_BLOCK(2U, -1L)
38 {
39 INST(8U, Opcode::Add).u64().Inputs(0U, 1U);
40 INST(9U, Opcode::Add).u64().Inputs(2U, 3U);
41 // should be moved down
42 INST(10U, Opcode::Add).u64().Inputs(8U, 9U);
43
44 INST(11U, Opcode::Add).u64().Inputs(4U, 5U);
45 INST(12U, Opcode::Add).u64().Inputs(6U, 7U);
46 INST(13U, Opcode::Add).u64().Inputs(11U, 12U);
47 // Grand total
48 INST(14U, Opcode::Add).u64().Inputs(10U, 13U);
49 INST(15U, Opcode::Return).u64().Inputs(14U);
50 }
51 }
52
53 ASSERT_TRUE(GetGraph()->RunPass<Scheduler>());
54
55 ASSERT_EQ(INS(8U).GetNext(), &INS(9U));
56 ASSERT_NE(INS(9U).GetNext(), &INS(10U));
57
58 EXPECT_TRUE((INS(11U).GetNext() == &INS(10U)) || (INS(12U).GetNext() == &INS(10U)));
59
60 ASSERT_EQ(INS(13U).GetNext(), &INS(14U));
61 ASSERT_EQ(INS(14U).GetNext(), &INS(15U));
62 }
63
TEST_F(SchedulerTest,LoadBarrier)64 TEST_F(SchedulerTest, LoadBarrier)
65 {
66 GRAPH(GetGraph())
67 {
68 PARAMETER(0U, 0U).s32(); // index
69 PARAMETER(1U, 1U).ref();
70 CONSTANT(2U, 42U);
71 CONSTANT(3U, 43U);
72 CONSTANT(4U, 44U);
73 CONSTANT(5U, 45U);
74 CONSTANT(6U, 46U);
75 CONSTANT(7U, 47U);
76 CONSTANT(8U, 48U);
77 CONSTANT(9U, 5U); // len array
78
79 BASIC_BLOCK(2U, -1L)
80 {
81 INST(10U, Opcode::Add).u64().Inputs(2U, 3U);
82 INST(11U, Opcode::Add).u64().Inputs(4U, 5U);
83 // should be moved down
84 INST(12U, Opcode::Add).u64().Inputs(10U, 11U);
85
86 INST(13U, Opcode::Add).u64().Inputs(6U, 7U);
87
88 INST(21U, Opcode::SafePoint).Inputs(0U, 1U).SrcVregs({0U, 1U});
89 INST(14U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
90 INST(15U, Opcode::BoundsCheck).s32().Inputs(9U, 0U, 14U);
91 // can't move up because of SafePoint
92 INST(16U, Opcode::LoadArray).u64().Inputs(1U, 15U);
93
94 INST(17U, Opcode::Add).u64().Inputs(8U, 16U);
95 INST(18U, Opcode::Add).u64().Inputs(13U, 17U);
96
97 INST(19U, Opcode::Add).u64().Inputs(12U, 18U);
98 INST(20U, Opcode::Return).u64().Inputs(19U);
99 }
100 }
101
102 ASSERT_TRUE(GetGraph()->RunPass<Scheduler>());
103
104 ASSERT_EQ(INS(11U).GetNext(), &INS(13U));
105 ASSERT_EQ(INS(13U).GetNext(), &INS(12U));
106 ASSERT_EQ(INS(12U).GetNext(), &INS(21U));
107 ASSERT_EQ(INS(21U).GetNext(), &INS(14U));
108 ASSERT_EQ(INS(15U).GetNext(), &INS(16U));
109 ASSERT_EQ(INS(16U).GetNext(), &INS(17U));
110 }
111
TEST_F(SchedulerTest,Load)112 TEST_F(SchedulerTest, Load)
113 {
114 GRAPH(GetGraph())
115 {
116 PARAMETER(0U, 0U).s32(); // index
117 PARAMETER(1U, 1U).ref();
118 CONSTANT(2U, 42U);
119 CONSTANT(3U, 43U);
120 CONSTANT(4U, 44U);
121 CONSTANT(5U, 45U);
122 CONSTANT(6U, 46U);
123 CONSTANT(7U, 47U);
124 CONSTANT(8U, 48U);
125 CONSTANT(9U, 5U); // len array
126
127 BASIC_BLOCK(2U, -1L)
128 {
129 INST(10U, Opcode::Add).u64().Inputs(2U, 3U);
130 INST(11U, Opcode::Add).u64().Inputs(4U, 5U);
131 // should be moved down
132 INST(12U, Opcode::Add).u64().Inputs(10U, 11U);
133
134 INST(13U, Opcode::Add).u64().Inputs(6U, 7U);
135
136 // all three should be moved up
137 INST(14U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
138 INST(15U, Opcode::BoundsCheck).s32().Inputs(9U, 0U, 14U);
139 INST(16U, Opcode::LoadArray).u64().Inputs(1U, 15U);
140
141 INST(17U, Opcode::Add).u64().Inputs(8U, 16U);
142 INST(18U, Opcode::Add).u64().Inputs(13U, 17U);
143
144 INST(19U, Opcode::Add).u64().Inputs(12U, 18U);
145 INST(20U, Opcode::Return).u64().Inputs(19U);
146 }
147 }
148
149 ASSERT_TRUE(GetGraph()->RunPass<Scheduler>());
150
151 ASSERT_EQ(INS(14U).GetNext(), &INS(10U));
152 ASSERT_EQ(INS(10U).GetNext(), &INS(15U));
153 ASSERT_EQ(INS(15U).GetNext(), &INS(11U));
154 ASSERT_EQ(INS(11U).GetNext(), &INS(16U));
155 ASSERT_EQ(INS(16U).GetNext(), &INS(13U));
156 ASSERT_EQ(INS(13U).GetNext(), &INS(12U));
157 ASSERT_EQ(INS(12U).GetNext(), &INS(17U));
158 ASSERT_EQ(INS(17U).GetNext(), &INS(18U));
159 ASSERT_EQ(INS(18U).GetNext(), &INS(19U));
160 ASSERT_EQ(INS(19U).GetNext(), &INS(20U));
161 }
162
TEST_F(SchedulerTest,FixSSInBBAfterScheduler)163 TEST_F(SchedulerTest, FixSSInBBAfterScheduler)
164 {
165 GRAPH(GetGraph())
166 {
167 CONSTANT(1U, 1U).s32();
168 CONSTANT(2U, 2U).s32();
169
170 BASIC_BLOCK(2U, -1L)
171 {
172 INST(4U, Opcode::SaveState).NoVregs();
173 INST(5U, Opcode::LoadAndInitClass).ref().Inputs(4U).TypeId(68U);
174 INST(6U, Opcode::SaveState).NoVregs();
175 INST(7U, Opcode::LoadConstArray).ref().Inputs(6U);
176 INST(8U, Opcode::Add).s32().Inputs(1U, 2U);
177 // LoadArray will move on one position down
178 INST(9U, Opcode::LoadArray).s32().Inputs(7U, 8U);
179 INST(10U, Opcode::SaveState).NoVregs();
180
181 INST(11U, Opcode::NOP);
182 INST(12U, Opcode::Return).s32().Inputs(9U);
183 }
184 }
185
186 ASSERT_TRUE(GetGraph()->RunPass<Scheduler>());
187
188 auto graph = CreateEmptyGraph();
189 GRAPH(graph)
190 {
191 CONSTANT(1U, 1U).s32();
192 CONSTANT(2U, 2U).s32();
193
194 BASIC_BLOCK(2U, -1L)
195 {
196 INST(4U, Opcode::SaveState).NoVregs();
197 INST(5U, Opcode::LoadAndInitClass).ref().Inputs(4U).TypeId(68U);
198 INST(6U, Opcode::SaveState).NoVregs();
199 INST(7U, Opcode::LoadConstArray).ref().Inputs(6U);
200 INST(8U, Opcode::Add).s32().Inputs(1U, 2U);
201
202 INST(10U, Opcode::SaveState).Inputs(7U).SrcVregs({VirtualRegister::BRIDGE});
203 INST(9U, Opcode::LoadArray).s32().Inputs(7U, 8U);
204
205 INST(11U, Opcode::NOP);
206 INST(12U, Opcode::Return).s32().Inputs(9U);
207 }
208 }
209
210 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
211 }
212
TEST_F(SchedulerTest,FixSSInBBAfterSchedulerOutToBlock)213 TEST_F(SchedulerTest, FixSSInBBAfterSchedulerOutToBlock)
214 {
215 GRAPH(GetGraph())
216 {
217 CONSTANT(1U, 1U).s32();
218 CONSTANT(2U, 2U).s32();
219
220 BASIC_BLOCK(2U, 3U)
221 {
222 INST(4U, Opcode::SaveState).NoVregs();
223 INST(5U, Opcode::LoadAndInitClass).ref().Inputs(4U).TypeId(68U);
224 INST(6U, Opcode::SaveState).NoVregs();
225 INST(7U, Opcode::LoadConstArray).ref().Inputs(6U);
226 }
227 BASIC_BLOCK(3U, -1L)
228 {
229 INST(8U, Opcode::Add).s32().Inputs(1U, 2U);
230 // LoadArray will move on one position down
231 INST(9U, Opcode::LoadArray).s32().Inputs(7U, 8U);
232 INST(10U, Opcode::SaveState).NoVregs();
233
234 INST(11U, Opcode::NOP);
235 INST(12U, Opcode::Return).s32().Inputs(9U);
236 }
237 }
238
239 ASSERT_TRUE(GetGraph()->RunPass<Scheduler>());
240
241 auto graph = CreateEmptyGraph();
242 GRAPH(graph)
243 {
244 CONSTANT(1U, 1U).s32();
245 CONSTANT(2U, 2U).s32();
246
247 BASIC_BLOCK(2U, 3U)
248 {
249 INST(4U, Opcode::SaveState).NoVregs();
250 INST(5U, Opcode::LoadAndInitClass).ref().Inputs(4U).TypeId(68U);
251 INST(6U, Opcode::SaveState).NoVregs();
252 INST(7U, Opcode::LoadConstArray).ref().Inputs(6U);
253 }
254 BASIC_BLOCK(3U, -1L)
255 {
256 INST(8U, Opcode::Add).s32().Inputs(1U, 2U);
257
258 INST(10U, Opcode::SaveState).Inputs(7U).SrcVregs({VirtualRegister::BRIDGE});
259 INST(9U, Opcode::LoadArray).s32().Inputs(7U, 8U);
260
261 INST(11U, Opcode::NOP);
262 INST(12U, Opcode::Return).s32().Inputs(9U);
263 }
264 }
265
266 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
267 }
268
TEST_F(SchedulerTest,LoadI)269 TEST_F(SchedulerTest, LoadI)
270 {
271 GRAPH(GetGraph())
272 {
273 PARAMETER(0U, 0U).u64();
274 PARAMETER(1U, 1U).ref();
275
276 BASIC_BLOCK(2U, -1L)
277 {
278 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
279 INST(3U, Opcode::BoundsCheckI).s32().Inputs(0U, 2U).Imm(1U);
280 INST(4U, Opcode::StoreArrayI).u64().Inputs(1U, 0U).Imm(1U);
281 INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
282 INST(6U, Opcode::BoundsCheckI).s32().Inputs(0U, 5U).Imm(0U);
283 INST(7U, Opcode::LoadArrayI).u64().Inputs(1U).Imm(0U);
284 INST(8U, Opcode::Return).u64().Inputs(7U);
285 }
286 }
287
288 ASSERT_FALSE(GetGraph()->RunPass<Scheduler>());
289 }
290
TEST_F(SchedulerTest,TrickyLoadI)291 TEST_F(SchedulerTest, TrickyLoadI)
292 {
293 GRAPH(GetGraph())
294 {
295 PARAMETER(0U, 0U).u64();
296 PARAMETER(1U, 1U).ref();
297 BASIC_BLOCK(2U, -1L)
298 {
299 INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
300 INST(6U, Opcode::BoundsCheckI).s32().Inputs(0U, 5U).Imm(0U);
301 // Manually moved here
302 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
303 INST(3U, Opcode::BoundsCheckI).s32().Inputs(0U, 2U).Imm(1U);
304 INST(4U, Opcode::StoreArrayI).u64().Inputs(1U, 0U).Imm(1U);
305 // But than all 3 may be moved below the load
306 INST(7U, Opcode::LoadArrayI).u64().Inputs(1U).Imm(0U);
307 INST(8U, Opcode::Return).u64().Inputs(7U);
308 }
309 }
310
311 ASSERT_TRUE(GetGraph()->RunPass<Scheduler>());
312
313 auto graph = CreateEmptyGraph();
314 GRAPH(graph)
315 {
316 PARAMETER(0U, 0U).u64();
317 PARAMETER(1U, 1U).ref();
318 BASIC_BLOCK(2U, -1L)
319 {
320 INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
321 INST(6U, Opcode::BoundsCheckI).s32().Inputs(0U, 5U).Imm(0U);
322 INST(7U, Opcode::LoadArrayI).u64().Inputs(1U).Imm(0U);
323
324 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
325 INST(3U, Opcode::BoundsCheckI).s32().Inputs(0U, 2U).Imm(1U);
326 INST(4U, Opcode::StoreArrayI).u64().Inputs(1U, 0U).Imm(1U);
327
328 INST(8U, Opcode::Return).u64().Inputs(7U);
329 }
330 }
331 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
332 }
333
TEST_F(SchedulerTest,MustAliasLoadI)334 TEST_F(SchedulerTest, MustAliasLoadI)
335 {
336 GRAPH(GetGraph())
337 {
338 PARAMETER(0U, 0U).u64();
339 PARAMETER(1U, 1U).ref();
340 BASIC_BLOCK(2U, -1L)
341 {
342 INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
343 INST(6U, Opcode::BoundsCheckI).s32().Inputs(0U, 5U).Imm(42U);
344 // Manually moved here
345 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
346 INST(3U, Opcode::BoundsCheckI).s32().Inputs(0U, 2U).Imm(42U);
347 INST(4U, Opcode::StoreArrayI).u64().Inputs(1U, 0U).Imm(42U);
348 // But than all 3 may be moved below the load
349 INST(7U, Opcode::LoadArrayI).u64().Inputs(1U).Imm(42U);
350 INST(8U, Opcode::Return).u64().Inputs(7U);
351 }
352 }
353
354 ASSERT_FALSE(GetGraph()->RunPass<Scheduler>());
355 }
356
TEST_F(SchedulerTest,LoadPair)357 TEST_F(SchedulerTest, LoadPair)
358 {
359 GRAPH(GetGraph())
360 {
361 PARAMETER(0U, 0U).s32(); // index
362 PARAMETER(1U, 1U).ref();
363 CONSTANT(11U, 41U);
364 CONSTANT(12U, 42U);
365 CONSTANT(13U, 43U);
366 CONSTANT(14U, 44U);
367 CONSTANT(15U, 45U);
368 CONSTANT(16U, 46U);
369 CONSTANT(17U, 47U);
370 CONSTANT(18U, 48U);
371 CONSTANT(19U, 49U);
372 CONSTANT(20U, 50U);
373 CONSTANT(21U, 51U);
374 CONSTANT(22U, 52U);
375 CONSTANT(23U, 53U);
376 CONSTANT(24U, 54U);
377
378 BASIC_BLOCK(2U, -1L)
379 {
380 INST(31U, Opcode::Add).u64().Inputs(11U, 12U);
381 INST(32U, Opcode::Add).u64().Inputs(13U, 14U);
382 INST(41U, Opcode::Add).u64().Inputs(31U, 32U);
383
384 INST(33U, Opcode::Add).u64().Inputs(15U, 16U);
385 INST(34U, Opcode::Add).u64().Inputs(17U, 18U);
386 INST(42U, Opcode::Add).u64().Inputs(33U, 34U);
387
388 INST(35U, Opcode::Add).u64().Inputs(19U, 20U);
389 INST(36U, Opcode::Add).u64().Inputs(21U, 22U);
390 INST(43U, Opcode::Add).u64().Inputs(35U, 36U);
391
392 INST(92U, Opcode::LoadArrayPair).u64().Inputs(1U, 0U);
393 INST(93U, Opcode::LoadPairPart).u64().Inputs(92U).Imm(0U);
394 INST(94U, Opcode::LoadPairPart).u64().Inputs(92U).Imm(1U);
395
396 INST(37U, Opcode::Add).u64().Inputs(23U, 93U);
397 INST(38U, Opcode::Add).u64().Inputs(24U, 94U);
398 INST(44U, Opcode::Add).u64().Inputs(37U, 38U);
399
400 INST(51U, Opcode::Add).u64().Inputs(41U, 42U);
401 INST(52U, Opcode::Add).u64().Inputs(43U, 44U);
402
403 INST(61U, Opcode::Add).u64().Inputs(51U, 52U);
404 INST(62U, Opcode::Return).u64().Inputs(61U);
405 }
406 }
407
408 ASSERT_TRUE(GetGraph()->RunPass<Scheduler>());
409
410 auto graph = CreateEmptyGraph();
411 GRAPH(graph)
412 {
413 PARAMETER(0U, 0U).s32(); // index
414 PARAMETER(1U, 1U).ref();
415 CONSTANT(11U, 41U);
416 CONSTANT(12U, 42U);
417 CONSTANT(13U, 43U);
418 CONSTANT(14U, 44U);
419 CONSTANT(15U, 45U);
420 CONSTANT(16U, 46U);
421 CONSTANT(17U, 47U);
422 CONSTANT(18U, 48U);
423 CONSTANT(19U, 49U);
424 CONSTANT(20U, 50U);
425 CONSTANT(21U, 51U);
426 CONSTANT(22U, 52U);
427 CONSTANT(23U, 53U);
428 CONSTANT(24U, 54U);
429
430 BASIC_BLOCK(2U, -1L)
431 {
432 INST(92U, Opcode::LoadArrayPair).u64().Inputs(1U, 0U);
433 INST(93U, Opcode::LoadPairPart).u64().Inputs(92U).Imm(0U);
434 INST(94U, Opcode::LoadPairPart).u64().Inputs(92U).Imm(1U);
435
436 INST(31U, Opcode::Add).u64().Inputs(11U, 12U);
437 INST(32U, Opcode::Add).u64().Inputs(13U, 14U);
438 INST(33U, Opcode::Add).u64().Inputs(15U, 16U);
439 INST(34U, Opcode::Add).u64().Inputs(17U, 18U);
440 INST(35U, Opcode::Add).u64().Inputs(19U, 20U);
441 INST(36U, Opcode::Add).u64().Inputs(21U, 22U);
442 INST(37U, Opcode::Add).u64().Inputs(23U, 93U);
443 INST(38U, Opcode::Add).u64().Inputs(24U, 94U);
444
445 INST(41U, Opcode::Add).u64().Inputs(31U, 32U);
446 INST(42U, Opcode::Add).u64().Inputs(33U, 34U);
447 INST(43U, Opcode::Add).u64().Inputs(35U, 36U);
448 INST(44U, Opcode::Add).u64().Inputs(37U, 38U);
449
450 INST(51U, Opcode::Add).u64().Inputs(41U, 42U);
451 INST(52U, Opcode::Add).u64().Inputs(43U, 44U);
452
453 INST(61U, Opcode::Add).u64().Inputs(51U, 52U);
454 INST(62U, Opcode::Return).u64().Inputs(61U);
455 }
456 }
457 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
458 }
459
TEST_F(SchedulerTest,NonVolatileLoadObject)460 TEST_F(SchedulerTest, NonVolatileLoadObject)
461 {
462 GRAPH(GetGraph())
463 {
464 PARAMETER(0U, 0U).ref();
465 PARAMETER(1U, 1U).s32();
466 PARAMETER(2U, 2U).s32();
467 PARAMETER(3U, 3U).s32();
468 BASIC_BLOCK(2U, -1L)
469 {
470 INST(4U, Opcode::Add).s32().Inputs(1U, 2U);
471 INST(5U, Opcode::Add).s32().Inputs(1U, 3U);
472 INST(6U, Opcode::Add).s32().Inputs(2U, 3U);
473 INST(7U, Opcode::Add).s32().Inputs(4U, 5U);
474 INST(8U, Opcode::Add).s32().Inputs(6U, 7U);
475 INST(9U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
476 INST(10U, Opcode::NullCheck).ref().Inputs(0U, 9U);
477 INST(11U, Opcode::LoadObject).s32().Inputs(10U).TypeId(152U);
478 INST(12U, Opcode::Add).s32().Inputs(8U, 11U);
479 INST(13U, Opcode::Return).s32().Inputs(12U);
480 }
481 }
482 ASSERT_TRUE(GetGraph()->RunPass<Scheduler>());
483
484 auto graph = CreateEmptyGraph();
485 GRAPH(graph)
486 {
487 PARAMETER(0U, 0U).ref();
488 PARAMETER(1U, 1U).s32();
489 PARAMETER(2U, 2U).s32();
490 PARAMETER(3U, 3U).s32();
491 BASIC_BLOCK(2U, -1L)
492 {
493 INST(9U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
494 INST(4U, Opcode::Add).s32().Inputs(1U, 2U);
495 INST(10U, Opcode::NullCheck).ref().Inputs(0U, 9U);
496 INST(5U, Opcode::Add).s32().Inputs(1U, 3U);
497 INST(11U, Opcode::LoadObject).s32().Inputs(10U).TypeId(152U);
498 INST(6U, Opcode::Add).s32().Inputs(2U, 3U);
499 INST(7U, Opcode::Add).s32().Inputs(4U, 5U);
500 INST(8U, Opcode::Add).s32().Inputs(6U, 7U);
501 INST(12U, Opcode::Add).s32().Inputs(8U, 11U);
502 INST(13U, Opcode::Return).s32().Inputs(12U);
503 }
504 }
505 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
506 }
507
TEST_F(SchedulerTest,VolatileLoadObject)508 TEST_F(SchedulerTest, VolatileLoadObject)
509 {
510 GRAPH(GetGraph())
511 {
512 PARAMETER(0U, 0U).ref();
513 PARAMETER(1U, 1U).s32();
514 PARAMETER(2U, 2U).s32();
515 PARAMETER(3U, 3U).s32();
516 BASIC_BLOCK(2U, -1L)
517 {
518 INST(4U, Opcode::Add).s32().Inputs(1U, 2U);
519 INST(5U, Opcode::Add).s32().Inputs(1U, 3U);
520 INST(6U, Opcode::Add).s32().Inputs(2U, 3U);
521 INST(7U, Opcode::Add).s32().Inputs(4U, 5U);
522 INST(8U, Opcode::Add).s32().Inputs(6U, 7U);
523 INST(9U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
524 INST(10U, Opcode::NullCheck).ref().Inputs(0U, 9U);
525 INST(11U, Opcode::LoadObject).s32().Inputs(10U).TypeId(152U).Volatile();
526 INST(12U, Opcode::Add).s32().Inputs(8U, 11U);
527 INST(13U, Opcode::Return).s32().Inputs(12U);
528 }
529 }
530 ASSERT_TRUE(GetGraph()->RunPass<Scheduler>());
531
532 auto graph = CreateEmptyGraph();
533 GRAPH(graph)
534 {
535 PARAMETER(0U, 0U).ref();
536 PARAMETER(1U, 1U).s32();
537 PARAMETER(2U, 2U).s32();
538 PARAMETER(3U, 3U).s32();
539 BASIC_BLOCK(2U, -1L)
540 {
541 INST(4U, Opcode::Add).s32().Inputs(1U, 2U);
542 INST(5U, Opcode::Add).s32().Inputs(1U, 3U);
543 INST(9U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
544 INST(6U, Opcode::Add).s32().Inputs(2U, 3U);
545 INST(7U, Opcode::Add).s32().Inputs(4U, 5U);
546 INST(10U, Opcode::NullCheck).ref().Inputs(0U, 9U);
547 INST(8U, Opcode::Add).s32().Inputs(6U, 7U);
548 INST(11U, Opcode::LoadObject).s32().Inputs(10U).TypeId(152U).Volatile();
549 INST(12U, Opcode::Add).s32().Inputs(8U, 11U);
550 INST(13U, Opcode::Return).s32().Inputs(12U);
551 }
552 }
553 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
554 }
555 // NOLINTEND(readability-magic-numbers)
556
557 } // namespace panda::compiler
558