1 /*
2 * Copyright (c) 2021-2025 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 "libpandabase/utils/utils.h"
17 #include "macros.h"
18 #include "unit_test.h"
19 #include "optimizer/ir/graph_cloner.h"
20 #include "optimizer/optimizations/peepholes.h"
21 #include "optimizer/optimizations/branch_elimination.h"
22 #include "optimizer/optimizations/lowering.h"
23 #include "optimizer/optimizations/cleanup.h"
24
25 namespace ark::compiler {
26 class PeepholesTest : public CommonTest {
27 public:
PeepholesTest()28 PeepholesTest()
29 : graph_(CreateGraphStartEndBlocks()),
30 defaultCompilerSafePointsRequireRegMap_(g_options.IsCompilerSafePointsRequireRegMap())
31 {
32 }
33
~PeepholesTest()34 ~PeepholesTest() override
35 {
36 g_options.SetCompilerSafePointsRequireRegMap(defaultCompilerSafePointsRequireRegMap_);
37 }
38
39 NO_COPY_SEMANTIC(PeepholesTest);
40 NO_MOVE_SEMANTIC(PeepholesTest);
41
GetGraph()42 Graph *GetGraph()
43 {
44 return graph_;
45 }
46
CheckCompare(DataType::Type paramType,ConditionCode origCc,ConditionCode cc)47 void CheckCompare(DataType::Type paramType, ConditionCode origCc, ConditionCode cc)
48 {
49 auto graph1 = CreateEmptyGraph();
50 GRAPH(graph1)
51 {
52 CONSTANT(0U, 0U);
53 PARAMETER(1U, 0U);
54 INS(1U).SetType(paramType);
55 PARAMETER(2U, 1U);
56 INS(2U).SetType(paramType);
57 BASIC_BLOCK(2U, 1U)
58 {
59 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
60 INST(4U, Opcode::Compare).b().CC(origCc).Inputs(3U, 0U);
61 INST(5U, Opcode::Return).b().Inputs(4U);
62 }
63 }
64 graph1->RunPass<Peepholes>();
65 GraphChecker(graph1).Check();
66
67 auto graph2 = CreateEmptyGraph();
68 GRAPH(graph2)
69 {
70 CONSTANT(0U, 0U);
71 PARAMETER(1U, 0U);
72 INS(1U).SetType(paramType);
73 PARAMETER(2U, 1U);
74 INS(2U).SetType(paramType);
75 BASIC_BLOCK(2U, 1U)
76 {
77 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
78 INST(4U, Opcode::Compare).b().CC(cc).Inputs(1U, 2U);
79 INST(5U, Opcode::Return).b().Inputs(4U);
80 }
81 }
82 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
83 }
84
CheckCompare(ConditionCode cc,int64_t cst,std::optional<uint64_t> expCst,bool expInv)85 void CheckCompare(ConditionCode cc, int64_t cst, std::optional<uint64_t> expCst, bool expInv)
86 {
87 auto graph = CreateEmptyGraph();
88 GRAPH(graph)
89 {
90 CONSTANT(0U, cst);
91 PARAMETER(1U, 0U).b();
92 BASIC_BLOCK(2U, 3U, 4U)
93 {
94 INST(3U, Opcode::Compare).b().CC(cc).Inputs(1U, 0U);
95 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
96 }
97 BASIC_BLOCK(3U, -1L)
98 {
99 INST(5U, Opcode::ReturnVoid);
100 }
101 BASIC_BLOCK(4U, -1L)
102 {
103 INST(6U, Opcode::ReturnVoid);
104 }
105 }
106 graph->RunPass<Peepholes>();
107 GraphChecker(graph).Check();
108
109 EXPECT_FALSE(INS(3U).HasUsers());
110 if (expCst.has_value()) {
111 auto inst = INS(4U).GetInput(0U).GetInst();
112 EXPECT_EQ(inst->GetOpcode(), Opcode::Constant);
113 EXPECT_EQ(inst->CastToConstant()->GetIntValue(), *expCst);
114 } else {
115 EXPECT_EQ(INS(4U).GetInput(0U).GetInst(), &INS(1U));
116 }
117 EXPECT_EQ(INS(4U).CastToIfImm()->GetImm(), 0U);
118 EXPECT_EQ(INS(4U).CastToIfImm()->GetCc() == CC_EQ, expInv);
119 }
120
CheckCast(DataType::Type srcType,DataType::Type tgtType,bool applied)121 void CheckCast(DataType::Type srcType, DataType::Type tgtType, bool applied)
122 {
123 if (srcType == DataType::REFERENCE || tgtType == DataType::REFERENCE) {
124 return;
125 }
126 auto graph1 = CreateEmptyGraph();
127 GRAPH(graph1)
128 {
129 PARAMETER(0U, 0U);
130 INS(0U).SetType(srcType);
131 BASIC_BLOCK(2U, 1U)
132 {
133 INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
134 INS(1U).SetType(tgtType);
135 INST(2U, Opcode::Return).Inputs(1U);
136 INS(2U).SetType(tgtType);
137 }
138 }
139 auto graph2 = CreateEmptyGraph();
140 if (applied) {
141 GRAPH(graph2)
142 {
143 PARAMETER(0U, 0U);
144 INS(0U).SetType(srcType);
145 BASIC_BLOCK(2U, 1U)
146 {
147 INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
148 INS(1U).SetType(tgtType);
149 INST(2U, Opcode::Return).Inputs(0U);
150 INS(2U).SetType(srcType);
151 }
152 }
153 } else {
154 GRAPH(graph2)
155 {
156 PARAMETER(0U, 0U);
157 INS(0U).SetType(srcType);
158 BASIC_BLOCK(2U, 1U)
159 {
160 INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
161 INS(1U).SetType(tgtType);
162 INST(2U, Opcode::Return).Inputs(1U);
163 INS(2U).SetType(tgtType);
164 }
165 }
166 }
167 ASSERT_EQ(graph1->RunPass<Peepholes>(), applied);
168 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
169 }
170
BuildCheckCastResJoined(DataType::Type srcType,DataType::Type mdlType,DataType::Type tgtType)171 Graph *BuildCheckCastResJoined(DataType::Type srcType, DataType::Type mdlType, DataType::Type tgtType)
172 {
173 auto graph = CreateEmptyGraph();
174 GRAPH(graph)
175 {
176 PARAMETER(0U, 0U);
177 INS(0U).SetType(srcType);
178 BASIC_BLOCK(2U, 1U)
179 {
180 INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
181 INS(1U).SetType(mdlType);
182 INST(2U, Opcode::Cast).SrcType(srcType).Inputs(0U);
183 INS(2U).SetType(tgtType);
184 INST(3U, Opcode::Return).Inputs(2U);
185 INS(3U).SetType(tgtType);
186 }
187 }
188 return graph;
189 }
190
BuildCheckCastResNotJoined(DataType::Type srcType,DataType::Type mdlType,DataType::Type tgtType)191 Graph *BuildCheckCastResNotJoined(DataType::Type srcType, DataType::Type mdlType, DataType::Type tgtType)
192 {
193 auto graph = CreateEmptyGraph();
194 GRAPH(graph)
195 {
196 PARAMETER(0U, 0U);
197 INS(0U).SetType(srcType);
198 BASIC_BLOCK(2U, 1U)
199 {
200 INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
201 INS(1U).SetType(mdlType);
202 INST(2U, Opcode::Cast).SrcType(mdlType).Inputs(1U);
203 INS(2U).SetType(tgtType);
204 INST(3U, Opcode::Return).Inputs(0U);
205 INS(3U).SetType(srcType);
206 }
207 }
208 return graph;
209 }
210
CheckCast(DataType::Type srcType,DataType::Type mdlType,DataType::Type tgtType,bool applied,bool joinCast)211 void CheckCast(DataType::Type srcType, DataType::Type mdlType, DataType::Type tgtType, bool applied, bool joinCast)
212 {
213 if (srcType == DataType::REFERENCE || tgtType == DataType::REFERENCE || mdlType == DataType::REFERENCE) {
214 return;
215 }
216 auto graph1 = CreateEmptyGraph();
217 GRAPH(graph1)
218 {
219 PARAMETER(0U, 0U);
220 INS(0U).SetType(srcType);
221 BASIC_BLOCK(2U, 1U)
222 {
223 INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
224 INS(1U).SetType(mdlType);
225 INST(2U, Opcode::Cast).SrcType(mdlType).Inputs(1U);
226 INS(2U).SetType(tgtType);
227 INST(3U, Opcode::Return).Inputs(2U);
228 INS(3U).SetType(tgtType);
229 }
230 }
231 Graph *graph2;
232 if (applied && joinCast) {
233 graph2 = BuildCheckCastResJoined(srcType, mdlType, tgtType);
234 } else if (applied) {
235 graph2 = BuildCheckCastResNotJoined(srcType, mdlType, tgtType);
236 } else {
237 graph2 = GraphCloner(graph1, GetAllocator(), GetLocalAllocator()).CloneGraph();
238 }
239 ASSERT_EQ(graph1->RunPass<Peepholes>(), applied);
240 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
241 }
242
CheckCast(int i,int j,int k)243 void CheckCast(int i, int j, int k)
244 {
245 if (i == j || j == k) {
246 return;
247 }
248 auto srcType = static_cast<DataType::Type>(i);
249 auto mdlType = static_cast<DataType::Type>(j);
250 auto tgtType = static_cast<DataType::Type>(k);
251 auto joinCast = DataType::GetTypeSize(srcType, GetArch()) > DataType::GetTypeSize(mdlType, GetArch()) &&
252 DataType::GetTypeSize(mdlType, GetArch()) > DataType::GetTypeSize(tgtType, GetArch());
253 CheckCast(srcType, mdlType, tgtType,
254 (srcType == tgtType &&
255 DataType::GetTypeSize(mdlType, GetArch()) > DataType::GetTypeSize(tgtType, GetArch())) ||
256 joinCast,
257 joinCast);
258 }
259
CheckCompareFoldIntoTest(uint64_t constant,ConditionCode cc,bool success,ConditionCode expectedCc=CC_EQ)260 void CheckCompareFoldIntoTest(uint64_t constant, ConditionCode cc, bool success, ConditionCode expectedCc = CC_EQ)
261 {
262 auto graph = CreateEmptyGraph();
263 GRAPH(graph)
264 {
265 PARAMETER(0U, 0U).u64();
266 PARAMETER(1U, 1U).u64();
267 CONSTANT(2U, constant);
268
269 BASIC_BLOCK(2U, -1L)
270 {
271 INST(3U, Opcode::And).u64().Inputs(0U, 1U);
272 INST(4U, Opcode::Compare).b().CC(cc).Inputs(3U, 2U);
273 INST(5U, Opcode::Return).b().Inputs(4U);
274 }
275 }
276
277 ASSERT_EQ(graph->RunPass<Peepholes>(), success);
278 if (!success) {
279 return;
280 }
281
282 graph->RunPass<Cleanup>();
283
284 auto expectedGraph = CreateEmptyGraph();
285 GRAPH(expectedGraph)
286 {
287 PARAMETER(0U, 0U).u64();
288 PARAMETER(1U, 1U).u64();
289
290 BASIC_BLOCK(2U, -1L)
291 {
292 INST(4U, Opcode::Compare).b().CC(expectedCc).Inputs(0U, 1U);
293 INST(5U, Opcode::Return).b().Inputs(4U);
294 }
295 }
296
297 ASSERT_TRUE(GraphComparator().Compare(graph, expectedGraph));
298 }
299
CheckIfAndZeroFoldIntoIfTest(uint64_t constant,ConditionCode cc,bool success,ConditionCode expectedCc=CC_EQ)300 void CheckIfAndZeroFoldIntoIfTest(uint64_t constant, ConditionCode cc, bool success,
301 ConditionCode expectedCc = CC_EQ)
302 {
303 auto graph = CreateEmptyGraph();
304 GRAPH(graph)
305 {
306 PARAMETER(0U, 0U).u64();
307 PARAMETER(1U, 1U).u64();
308 CONSTANT(2U, constant);
309 CONSTANT(3U, -1L);
310 CONSTANT(4U, -2L);
311
312 BASIC_BLOCK(2U, 3U, 4U)
313 {
314 INST(5U, Opcode::And).u64().Inputs(0U, 1U);
315 INST(6U, Opcode::If).SrcType(DataType::UINT64).CC(cc).Inputs(5U, 2U);
316 }
317
318 BASIC_BLOCK(3U, 4U) {}
319
320 BASIC_BLOCK(4U, -1L)
321 {
322 INST(7U, Opcode::Phi).s64().Inputs(3U, 4U);
323 INST(8U, Opcode::Return).s64().Inputs(7U);
324 }
325 }
326
327 ASSERT_EQ(graph->RunPass<Peepholes>(), success);
328 if (!success) {
329 return;
330 }
331
332 graph->RunPass<Cleanup>();
333
334 auto expectedGraph = CreateEmptyGraph();
335 GRAPH(expectedGraph)
336 {
337 PARAMETER(0U, 0U).u64();
338 PARAMETER(1U, 1U).u64();
339 CONSTANT(3U, -1L);
340 CONSTANT(4U, -2L);
341
342 BASIC_BLOCK(2U, 3U, 4U)
343 {
344 INST(6U, Opcode::If).SrcType(DataType::UINT64).CC(expectedCc).Inputs(0U, 1U);
345 }
346
347 BASIC_BLOCK(3U, 4U) {}
348
349 BASIC_BLOCK(4U, -1L)
350 {
351 INST(7U, Opcode::Phi).s64().Inputs(3U, 4U);
352 INST(8U, Opcode::Return).s64().Inputs(7U);
353 }
354 }
355
356 ASSERT_TRUE(GraphComparator().Compare(graph, expectedGraph));
357 }
358
CheckCompareLenArrayWithZeroTest(int64_t constant,ConditionCode cc,std::optional<bool> expectedValue,bool swap=false)359 void CheckCompareLenArrayWithZeroTest(int64_t constant, ConditionCode cc, std::optional<bool> expectedValue,
360 bool swap = false)
361 {
362 auto graph = CreateEmptyGraph();
363 GRAPH(graph)
364 {
365 PARAMETER(0U, 0U).ref();
366 CONSTANT(1U, constant);
367 BASIC_BLOCK(2U, -1L)
368 {
369 INST(3U, Opcode::LenArray).s32().Inputs(0U);
370 if (swap) {
371 INST(4U, Opcode::Compare).b().CC(cc).Inputs(1U, 3U);
372 } else {
373 INST(4U, Opcode::Compare).b().CC(cc).Inputs(3U, 1U);
374 }
375 INST(5U, Opcode::Return).b().Inputs(4U);
376 }
377 }
378
379 ASSERT_EQ(graph->RunPass<Peepholes>(), expectedValue.has_value());
380 if (!expectedValue.has_value()) {
381 return;
382 }
383
384 graph->RunPass<Cleanup>();
385
386 auto expectedGraph = CreateEmptyGraph();
387 GRAPH(expectedGraph)
388 {
389 CONSTANT(1U, *expectedValue);
390 BASIC_BLOCK(2U, -1L)
391 {
392 INST(2U, Opcode::Return).b().Inputs(1U);
393 }
394 }
395
396 ASSERT_TRUE(GraphComparator().Compare(graph, expectedGraph));
397 }
398
399 void CastTest2Addition1MainLoop(int i, int j);
400
401 private:
402 Graph *graph_ {nullptr};
403
404 private:
405 bool defaultCompilerSafePointsRequireRegMap_;
406 };
407
408 // NOLINTBEGIN(readability-magic-numbers)
TEST_F(PeepholesTest,TestAnd1)409 TEST_F(PeepholesTest, TestAnd1)
410 {
411 // case 1:
412 // 0.i64 Const ...
413 // 1.i64 AND v0, v5
414 // ===>
415 // 0.i64 Const 25
416 // 1.i64 AND v5, v0
417 GRAPH(GetGraph())
418 {
419 PARAMETER(0U, 1U).u64();
420 CONSTANT(1U, 2U);
421 BASIC_BLOCK(2U, -1L)
422 {
423 INST(2U, Opcode::And).u64().Inputs(1U, 0U);
424 INST(3U, Opcode::Return).u64().Inputs(2U);
425 }
426 }
427 GetGraph()->RunPass<Peepholes>();
428 GraphChecker(GetGraph()).Check();
429 ASSERT_EQ(INS(2U).GetInput(0U).GetInst(), &INS(0U));
430 ASSERT_EQ(INS(2U).GetInput(1U).GetInst(), &INS(1U));
431 ASSERT_EQ(INS(1U).GetUsers().Front().GetIndex(), 1U);
432 ASSERT_EQ(INS(0U).GetUsers().Front().GetIndex(), 0U);
433 }
434
TEST_F(PeepholesTest,TestAnd2)435 TEST_F(PeepholesTest, TestAnd2)
436 {
437 // case 2:
438 // 0.i64 Const 0xFFF..FF
439 // 1.i64 AND v5, v0
440 // 2.i64 INS which use v1
441 // ===>
442 // 0.i64 Const 0xFFF..FF
443 // 1.i64 AND v5, v0
444 // 2.i64 INS which use v5
445 GRAPH(GetGraph())
446 {
447 PARAMETER(0U, 1U).u64();
448 CONSTANT(1U, -1L);
449 BASIC_BLOCK(2U, -1L)
450 {
451 INST(2U, Opcode::And).u64().Inputs(0U, 1U);
452 INST(3U, Opcode::Return).u64().Inputs(2U);
453 }
454 }
455 GetGraph()->RunPass<Peepholes>();
456 GraphChecker(GetGraph()).Check();
457 ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
458 }
459
TEST_F(PeepholesTest,TestAnd2Addition)460 TEST_F(PeepholesTest, TestAnd2Addition)
461 {
462 // Case 1 + Case 2
463 GRAPH(GetGraph())
464 {
465 PARAMETER(0U, 1U).u64();
466 CONSTANT(1U, -1L);
467 BASIC_BLOCK(2U, -1L)
468 {
469 INST(2U, Opcode::And).u64().Inputs(1U, 0U);
470 INST(3U, Opcode::Return).u64().Inputs(2U);
471 }
472 }
473 GetGraph()->RunPass<Peepholes>();
474 GraphChecker(GetGraph()).Check();
475 ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
476 ASSERT_EQ(INS(1U).GetUsers().Front().GetIndex(), 1U);
477 ASSERT_EQ(INS(0U).GetUsers().Front().GetIndex(), 0U);
478 }
479
TEST_F(PeepholesTest,TestAnd3)480 TEST_F(PeepholesTest, TestAnd3)
481 {
482 // case 3:
483 // 1.i64 AND v5, v5
484 // 2.i64 INS which use v1
485 // ===>
486 // 1.i64 AND v5, v5
487 // 2.i64 INS which use v5
488 GRAPH(GetGraph())
489 {
490 PARAMETER(0U, 1U).u64();
491 BASIC_BLOCK(2U, -1L)
492 {
493 INST(2U, Opcode::And).u64().Inputs(0U, 0U);
494 INST(3U, Opcode::Return).u64().Inputs(2U);
495 }
496 }
497 GetGraph()->RunPass<Peepholes>();
498 GraphChecker(GetGraph()).Check();
499 ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
500 }
501
TEST_F(PeepholesTest,TestAnd3Addition)502 TEST_F(PeepholesTest, TestAnd3Addition)
503 {
504 // case 3:
505 // but input's type not equal with and-inst's type
506 GRAPH(GetGraph())
507 {
508 PARAMETER(0U, 1U).s32();
509 BASIC_BLOCK(2U, -1L)
510 {
511 INST(2U, Opcode::And).s16().Inputs(0U, 0U);
512 INST(3U, Opcode::Return).s32().Inputs(2U);
513 }
514 }
515 GetGraph()->RunPass<Peepholes>();
516 GraphChecker(GetGraph()).Check();
517 ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(2U));
518 }
519
TEST_F(PeepholesTest,TestAnd4)520 TEST_F(PeepholesTest, TestAnd4)
521 {
522 // case 4: De Morgan rules
523 // 2.i64 not v0 -> {4}
524 // 3.i64 not v1 -> {4}
525 // 4.i64 AND v2, v3
526 // ===>
527 // 5.i64 OR v0, v1
528 // 6.i64 not v5
529 GRAPH(GetGraph())
530 {
531 PARAMETER(0U, 1U).u64();
532 PARAMETER(1U, 2U).u64();
533 BASIC_BLOCK(2U, -1L)
534 {
535 INST(2U, Opcode::Not).u64().Inputs(0U);
536 INST(3U, Opcode::Not).u64().Inputs(1U);
537 INST(4U, Opcode::And).u64().Inputs(2U, 3U);
538 INST(5U, Opcode::Return).u64().Inputs(4U);
539 }
540 }
541 GetGraph()->RunPass<Peepholes>();
542 GraphChecker(GetGraph()).Check();
543 auto notInst = INS(5U).GetInput(0U).GetInst();
544 ASSERT_EQ(notInst->GetOpcode(), Opcode::Not);
545 auto orInst = notInst->GetInput(0U).GetInst();
546 ASSERT_EQ(orInst->GetOpcode(), Opcode::Or);
547 ASSERT_EQ(orInst->GetInput(0U).GetInst(), &INS(0U));
548 ASSERT_EQ(orInst->GetInput(1U).GetInst(), &INS(1U));
549 }
550
TEST_F(PeepholesTest,TestAnd4Addition)551 TEST_F(PeepholesTest, TestAnd4Addition)
552 {
553 // Case 4, but NOT-inst have more than 1 user
554 GRAPH(GetGraph())
555 {
556 PARAMETER(0U, 1U).u64();
557 PARAMETER(1U, 2U).u64();
558 BASIC_BLOCK(2U, -1L)
559 {
560 INST(2U, Opcode::Not).u64().Inputs(0U);
561 INST(3U, Opcode::Not).u64().Inputs(1U);
562 INST(4U, Opcode::And).u64().Inputs(2U, 3U);
563 INST(5U, Opcode::Not).u64().Inputs(2U);
564 INST(6U, Opcode::Not).u64().Inputs(3U);
565 INST(20U, Opcode::SaveState).NoVregs();
566 INST(7U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 6U, 20U);
567 INST(8U, Opcode::Return).u64().Inputs(7U);
568 }
569 }
570 GetGraph()->RunPass<Peepholes>();
571 GraphChecker(GetGraph()).Check();
572 auto andInst = INS(7U).GetInput(0U).GetInst();
573 ASSERT_EQ(andInst->GetOpcode(), Opcode::And);
574 }
575
TEST_F(PeepholesTest,TestOr1)576 TEST_F(PeepholesTest, TestOr1)
577 {
578 // case 1:
579 // 0.i64 Const ...
580 // 1.i64 Or v0, v5
581 // ===>
582 // 0.i64 Const 25
583 // 1.i64 Or v5, v0
584 GRAPH(GetGraph())
585 {
586 PARAMETER(0U, 1U).u64();
587 CONSTANT(1U, 2U);
588 BASIC_BLOCK(2U, -1L)
589 {
590 INST(2U, Opcode::Or).u64().Inputs(1U, 0U);
591 INST(3U, Opcode::Return).u64().Inputs(2U);
592 }
593 }
594 GetGraph()->RunPass<Peepholes>();
595 GraphChecker(GetGraph()).Check();
596 ASSERT_EQ(INS(2U).GetInput(0U).GetInst(), &INS(0U));
597 ASSERT_EQ(INS(2U).GetInput(1U).GetInst(), &INS(1U));
598 ASSERT_EQ(INS(1U).GetUsers().Front().GetIndex(), 1U);
599 ASSERT_EQ(INS(0U).GetUsers().Front().GetIndex(), 0U);
600 }
601
TEST_F(PeepholesTest,TestOr2)602 TEST_F(PeepholesTest, TestOr2)
603 {
604 // case 2:
605 // 0.i64 Const 0x000..00
606 // 1.i64 OR v5, v0
607 // 2.i64 INS which use v1
608 // ===>
609 // 0.i64 Const 0x000..00
610 // 1.i64 OR v5, v0
611 // 2.i64 INS which use v5
612 GRAPH(GetGraph())
613 {
614 PARAMETER(0U, 1U).u64();
615 CONSTANT(1U, 0U);
616 BASIC_BLOCK(2U, -1L)
617 {
618 INST(2U, Opcode::Or).u64().Inputs(1U, 0U);
619 INST(3U, Opcode::Return).u64().Inputs(2U);
620 }
621 }
622 GetGraph()->RunPass<Peepholes>();
623 GraphChecker(GetGraph()).Check();
624 ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
625 }
626
TEST_F(PeepholesTest,AddConstantTest1)627 TEST_F(PeepholesTest, AddConstantTest1)
628 {
629 GRAPH(GetGraph())
630 {
631 PARAMETER(0U, 0U).u64();
632 PARAMETER(1U, 1U).u64();
633 CONSTANT(2U, 1U);
634 CONSTANT(3U, 0U);
635
636 BASIC_BLOCK(2U, -1L)
637 {
638 INST(4U, Opcode::Add).u64().Inputs(2U, 0U);
639 INST(5U, Opcode::Add).u64().Inputs(3U, 1U);
640 INST(20U, Opcode::SaveState).NoVregs();
641 INST(6U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 20U);
642 INST(7U, Opcode::Return).u64().Inputs(6U);
643 }
644 }
645 GetGraph()->RunPass<Peepholes>();
646 ASSERT_TRUE(CheckInputs(INS(4U), {0U, 2U}));
647 ASSERT_TRUE(CheckInputs(INS(5U), {1U, 3U}));
648 ASSERT_TRUE(CheckInputs(INS(6U), {4U, 1U, 20U}));
649
650 ASSERT_TRUE(CheckUsers(INS(0U), {4U}));
651 ASSERT_TRUE(CheckUsers(INS(2U), {4U}));
652 ASSERT_TRUE(CheckUsers(INS(3U), {5U}));
653 ASSERT_TRUE(INS(5U).GetUsers().Empty());
654 }
655
TEST_F(PeepholesTest,AddConstantTest2)656 TEST_F(PeepholesTest, AddConstantTest2)
657 {
658 GRAPH(GetGraph())
659 {
660 PARAMETER(0U, 0U).u64();
661 CONSTANT(1U, 5U);
662 CONSTANT(2U, 6U);
663
664 BASIC_BLOCK(2U, -1L)
665 {
666 INST(3U, Opcode::Add).u64().Inputs(0U, 1U);
667 INST(4U, Opcode::Sub).u64().Inputs(0U, 1U);
668
669 INST(5U, Opcode::Add).u64().Inputs(2U, 3U);
670 INST(6U, Opcode::Add).u64().Inputs(2U, 4U);
671 INST(20U, Opcode::SaveState).NoVregs();
672 INST(7U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 20U);
673 INST(8U, Opcode::Return).u64().Inputs(7U);
674 }
675 }
676 GetGraph()->RunPass<Peepholes>();
677
678 auto const3 = INS(2U).GetNext();
679 ASSERT_TRUE(const3 != nullptr);
680 auto const4 = const3->GetNext();
681 ASSERT_TRUE(const4 != nullptr && const4->GetNext() == nullptr);
682
683 ASSERT_TRUE(INS(5U).GetInput(0U) == &INS(0U) && INS(5U).GetInput(1U) == const3);
684 ASSERT_TRUE(INS(6U).GetInput(0U) == &INS(0U) && INS(6U).GetInput(1U) == const4);
685
686 ASSERT_TRUE(CheckUsers(INS(0U), {3U, 4U, 5U, 6U}));
687 ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U}));
688 ASSERT_TRUE(CheckUsers(*const3, {5U}));
689 ASSERT_TRUE(CheckUsers(*const4, {6U}));
690 ASSERT_TRUE(INS(2U).GetUsers().Empty());
691 }
692
TEST_F(PeepholesTest,AddConstantTest3)693 TEST_F(PeepholesTest, AddConstantTest3)
694 {
695 GRAPH(GetGraph())
696 {
697 PARAMETER(0U, 0U).u32();
698 CONSTANT(1U, 5U);
699 CONSTANT(2U, 6U);
700
701 BASIC_BLOCK(2U, -1L)
702 {
703 INST(3U, Opcode::Add).u16().Inputs(0U, 1U);
704 INST(4U, Opcode::Sub).u16().Inputs(0U, 1U);
705
706 INST(5U, Opcode::Add).u32().Inputs(2U, 3U);
707 INST(6U, Opcode::Add).u32().Inputs(2U, 4U);
708 INST(20U, Opcode::SaveState).NoVregs();
709 INST(7U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 20U);
710 INST(8U, Opcode::Return).u64().Inputs(7U);
711 }
712 }
713 GetGraph()->RunPass<Peepholes>();
714
715 ASSERT_TRUE(INS(2U).GetNext() == nullptr);
716
717 ASSERT_TRUE(CheckInputs(INS(3U), {0U, 1U}));
718 ASSERT_TRUE(CheckInputs(INS(4U), {0U, 1U}));
719 ASSERT_TRUE(CheckInputs(INS(5U), {3U, 2U}));
720 ASSERT_TRUE(CheckInputs(INS(6U), {4U, 2U}));
721
722 ASSERT_TRUE(CheckUsers(INS(0U), {3U, 4U}));
723 ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U}));
724 ASSERT_TRUE(CheckUsers(INS(2U), {5U, 6U}));
725 ASSERT_TRUE(CheckUsers(INS(3U), {5U}));
726 ASSERT_TRUE(CheckUsers(INS(4U), {6U}));
727 }
728
TEST_F(PeepholesTest,AddNegTest1)729 TEST_F(PeepholesTest, AddNegTest1)
730 {
731 GRAPH(GetGraph())
732 {
733 PARAMETER(0U, 0U).u64();
734 PARAMETER(1U, 1U).u64();
735
736 BASIC_BLOCK(2U, -1L)
737 {
738 INST(2U, Opcode::Neg).u64().Inputs(0U);
739 INST(3U, Opcode::Neg).u64().Inputs(1U);
740
741 INST(4U, Opcode::Add).u64().Inputs(2U, 3U);
742 INST(5U, Opcode::Return).u64().Inputs(4U);
743 }
744 }
745 GetGraph()->RunPass<Peepholes>();
746
747 auto newNeg = INS(4U).GetNext();
748
749 ASSERT_TRUE(CheckUsers(INS(0U), {2U, 4U}));
750 ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U}));
751 ASSERT_TRUE(INS(2U).GetUsers().Empty());
752 ASSERT_TRUE(INS(3U).GetUsers().Empty());
753
754 ASSERT(CheckInputs(INS(4U), {0U, 1U}));
755
756 auto user = INS(4U).GetUsers().begin();
757 ASSERT_TRUE(user->GetInst() == newNeg);
758 ASSERT_FALSE(++user != INS(4U).GetUsers().end());
759
760 ASSERT_TRUE(newNeg->GetInput(0U) == &INS(4U));
761 ASSERT_TRUE(CheckUsers(*newNeg, {5U}));
762
763 ASSERT_TRUE(INS(5U).GetInput(0U) == newNeg);
764 }
765
TEST_F(PeepholesTest,AddNegTest2)766 TEST_F(PeepholesTest, AddNegTest2)
767 {
768 GRAPH(GetGraph())
769 {
770 PARAMETER(0U, 0U).u64();
771 PARAMETER(1U, 1U).u64();
772
773 BASIC_BLOCK(2U, -1L)
774 {
775 INST(2U, Opcode::Neg).u64().Inputs(0U);
776 INST(3U, Opcode::Neg).u64().Inputs(1U);
777
778 INST(4U, Opcode::Add).u64().Inputs(2U, 3U);
779 INST(20U, Opcode::SaveState).NoVregs();
780 INST(6U, Opcode::CallStatic).u64().InputsAutoType(2U, 4U, 20U);
781 INST(5U, Opcode::Return).u64().Inputs(6U);
782 }
783 }
784 GetGraph()->RunPass<Peepholes>();
785
786 ASSERT_TRUE(CheckUsers(INS(0U), {2U}));
787 ASSERT_TRUE(CheckUsers(INS(1U), {3U}));
788
789 ASSERT_TRUE(CheckInputs(INS(2U), {0U}));
790 ASSERT_TRUE(CheckUsers(INS(2U), {4U, 6U}));
791 ASSERT_TRUE(CheckInputs(INS(3U), {1U}));
792 ASSERT_TRUE(CheckUsers(INS(3U), {4U}));
793
794 ASSERT_TRUE(CheckInputs(INS(4U), {2U, 3U}));
795 }
796
TEST_F(PeepholesTest,AddNegTest3)797 TEST_F(PeepholesTest, AddNegTest3)
798 {
799 GRAPH(GetGraph())
800 {
801 PARAMETER(0U, 0U).u64();
802 PARAMETER(1U, 1U).u64();
803 CONSTANT(8U, 1U);
804 CONSTANT(9U, 2U);
805
806 BASIC_BLOCK(2U, -1L)
807 {
808 INST(2U, Opcode::Neg).u64().Inputs(0U);
809 INST(3U, Opcode::Neg).u64().Inputs(1U);
810
811 INST(4U, Opcode::Add).u64().Inputs(2U, 8U);
812 INST(5U, Opcode::Add).u64().Inputs(3U, 9U);
813
814 INST(6U, Opcode::Add).u64().Inputs(2U, 3U);
815 INST(20U, Opcode::SaveState).NoVregs();
816 INST(10U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 6U, 20U);
817 INST(7U, Opcode::Return).u64().Inputs(10U);
818 }
819 }
820 GetGraph()->RunPass<Peepholes>();
821 ASSERT_TRUE(CheckUsers(INS(0U), {2U}));
822 ASSERT_TRUE(CheckUsers(INS(1U), {3U}));
823 ASSERT_TRUE(CheckUsers(INS(2U), {4U, 6U}));
824 ASSERT_TRUE(CheckUsers(INS(3U), {5U, 6U}));
825
826 ASSERT(CheckInputs(INS(4U), {2U, 8U}));
827 ASSERT(CheckInputs(INS(5U), {3U, 9U}));
828
829 ASSERT_TRUE(CheckInputs(INS(6U), {2U, 3U}));
830 ASSERT_TRUE(CheckUsers(INS(6U), {10U}));
831 ASSERT_TRUE(INS(6U).GetNext()->GetNext() == &INS(10U));
832
833 ASSERT_TRUE(CheckInputs(INS(7U), {10U}));
834 }
835
TEST_F(PeepholesTest,AddNegTest4)836 TEST_F(PeepholesTest, AddNegTest4)
837 {
838 GRAPH(GetGraph())
839 {
840 PARAMETER(0U, 0U).u64();
841 PARAMETER(1U, 1U).u64();
842
843 BASIC_BLOCK(2U, -1L)
844 {
845 INST(2U, Opcode::Neg).u64().Inputs(0U);
846 INST(3U, Opcode::Neg).u64().Inputs(1U);
847
848 INST(4U, Opcode::Add).u64().Inputs(0U, 3U);
849 INST(5U, Opcode::Add).u64().Inputs(2U, 1U);
850 INST(20U, Opcode::SaveState).NoVregs();
851 INST(7U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 20U);
852 INST(6U, Opcode::Return).u64().Inputs(7U);
853 }
854 }
855 GetGraph()->RunPass<Peepholes>();
856
857 ASSERT_TRUE(CheckUsers(INS(0U), {2U, 4U, 5U}));
858 ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U, 5U}));
859
860 ASSERT_TRUE(INS(2U).GetUsers().Empty());
861 ASSERT_TRUE(INS(3U).GetUsers().Empty());
862
863 ASSERT_TRUE(CheckInputs(INS(4U), {0U, 1U}));
864 ASSERT_TRUE(INS(4U).GetOpcode() == Opcode::Sub);
865
866 ASSERT_TRUE(CheckInputs(INS(5U), {1U, 0U}));
867 ASSERT_TRUE(INS(5U).GetOpcode() == Opcode::Sub);
868 }
869
TEST_F(PeepholesTest,AddNegConstOne)870 TEST_F(PeepholesTest, AddNegConstOne)
871 {
872 GRAPH(GetGraph())
873 {
874 CONSTANT(0U, 1U);
875 BASIC_BLOCK(2U, -1L)
876 {
877 INST(1U, Opcode::SaveState).NoVregs();
878 INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
879 INST(3U, Opcode::Neg).s32().Inputs(2U);
880 INST(4U, Opcode::Add).s32().Inputs(3U, 0U);
881 INST(5U, Opcode::Return).s32().Inputs(4U);
882 }
883 }
884
885 auto graph = CreateEmptyGraph();
886 GRAPH(graph)
887 {
888 CONSTANT(6U, 0U);
889 BASIC_BLOCK(2U, -1L)
890 {
891 INST(1U, Opcode::SaveState).NoVregs();
892 INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
893 INST(7U, Opcode::Compare).s32().b().CC(ConditionCode::CC_EQ).SetType(DataType::BOOL).Inputs(2U, 6U);
894 INST(5U, Opcode::Return).s32().Inputs(7U);
895 }
896 }
897
898 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
899 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
900
901 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
902 }
903
TEST_F(PeepholesTest,SameAddAndSubTest)904 TEST_F(PeepholesTest, SameAddAndSubTest)
905 {
906 GRAPH(GetGraph())
907 {
908 PARAMETER(0U, 0U).u64();
909 PARAMETER(1U, 1U).u64();
910
911 BASIC_BLOCK(2U, -1L)
912 {
913 INST(2U, Opcode::Sub).u64().Inputs(0U, 1U);
914 INST(3U, Opcode::Add).u64().Inputs(2U, 1U);
915 INST(4U, Opcode::Add).u64().Inputs(1U, 2U);
916 INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
917
918 INST(6U, Opcode::Add).u32().Inputs(1U, 2U);
919 INST(7U, Opcode::Add).u32().Inputs(2U, 1U);
920 INST(8U, Opcode::Add).u32().Inputs(6U, 7U);
921 INST(20U, Opcode::SaveState).NoVregs();
922 INST(10U, Opcode::CallStatic).u64().InputsAutoType(5U, 8U, 20U);
923 INST(9U, Opcode::Return).u64().Inputs(10U);
924 }
925 }
926 GetGraph()->RunPass<Peepholes>();
927
928 ASSERT_TRUE(INS(3U).GetUsers().Empty());
929 ASSERT_TRUE(INS(4U).GetUsers().Empty());
930 ASSERT_TRUE(CheckInputs(INS(5U), {0U, 0U}));
931
932 ASSERT_TRUE(CheckInputs(INS(6U), {1U, 2U}));
933 ASSERT_TRUE(CheckInputs(INS(7U), {2U, 1U}));
934 ASSERT_TRUE(CheckInputs(INS(8U), {6U, 7U}));
935 }
936
937 // (a - b) + (c + b) -> a + c
TEST_F(PeepholesTest,AddSubAndAddSameOperandTest1)938 TEST_F(PeepholesTest, AddSubAndAddSameOperandTest1)
939 {
940 GRAPH(GetGraph())
941 {
942 PARAMETER(0U, 0U).u64();
943 PARAMETER(1U, 1U).u64();
944 PARAMETER(2U, 2U).u64();
945
946 BASIC_BLOCK(2U, -1L)
947 {
948 INST(3U, Opcode::Sub).u64().Inputs(0U, 1U);
949 INST(4U, Opcode::Add).u64().Inputs(2U, 1U);
950 INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
951 INST(6U, Opcode::Return).u64().Inputs(5U);
952 }
953 }
954 GetGraph()->RunPass<Peepholes>();
955 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
956 ASSERT_TRUE(CheckInputs(INS(5U), {0U, 2U}));
957 }
958
959 // (a - b) + (b + c) -> a + c
TEST_F(PeepholesTest,AddSubAndAddSameOperandTest2)960 TEST_F(PeepholesTest, AddSubAndAddSameOperandTest2)
961 {
962 GRAPH(GetGraph())
963 {
964 PARAMETER(0U, 0U).u64();
965 PARAMETER(1U, 1U).u64();
966 PARAMETER(2U, 2U).u64();
967
968 BASIC_BLOCK(2U, -1L)
969 {
970 INST(3U, Opcode::Sub).u64().Inputs(0U, 1U);
971 INST(4U, Opcode::Add).u64().Inputs(1U, 2U);
972 INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
973 INST(6U, Opcode::Return).u64().Inputs(5U);
974 }
975 }
976 GetGraph()->RunPass<Peepholes>();
977 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
978 ASSERT_TRUE(CheckInputs(INS(5U), {0U, 2U}));
979 }
980
981 // (a + b) + (c - b) -> c + a
TEST_F(PeepholesTest,AddAddAndSubSameOperandTest1)982 TEST_F(PeepholesTest, AddAddAndSubSameOperandTest1)
983 {
984 GRAPH(GetGraph())
985 {
986 PARAMETER(0U, 0U).u64();
987 PARAMETER(1U, 1U).u64();
988 PARAMETER(2U, 2U).u64();
989
990 BASIC_BLOCK(2U, -1L)
991 {
992 INST(3U, Opcode::Sub).u64().Inputs(2U, 1U);
993 INST(4U, Opcode::Add).u64().Inputs(0U, 1U);
994 INST(5U, Opcode::Add).u64().Inputs(4U, 3U);
995 INST(6U, Opcode::Return).u64().Inputs(5U);
996 }
997 }
998 GetGraph()->RunPass<Peepholes>();
999 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
1000 ASSERT_TRUE(CheckInputs(INS(5U), {2U, 0U}));
1001 }
1002
1003 // (b + a) + (c - b) -> c + a
TEST_F(PeepholesTest,AddAddAndSubSameOperandTest2)1004 TEST_F(PeepholesTest, AddAddAndSubSameOperandTest2)
1005 {
1006 GRAPH(GetGraph())
1007 {
1008 PARAMETER(0U, 0U).u64();
1009 PARAMETER(1U, 1U).u64();
1010 PARAMETER(2U, 2U).u64();
1011
1012 BASIC_BLOCK(2U, -1L)
1013 {
1014 INST(3U, Opcode::Sub).u64().Inputs(2U, 1U);
1015 INST(4U, Opcode::Add).u64().Inputs(1U, 0U);
1016 INST(5U, Opcode::Add).u64().Inputs(4U, 3U);
1017 INST(6U, Opcode::Return).u64().Inputs(5U);
1018 }
1019 }
1020 GetGraph()->RunPass<Peepholes>();
1021 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
1022 ASSERT_TRUE(CheckInputs(INS(5U), {2U, 0U}));
1023 }
1024
1025 // (a - b) + (b - c) -> a - c
TEST_F(PeepholesTest,AddSubAndSubSameOperandTest1)1026 TEST_F(PeepholesTest, AddSubAndSubSameOperandTest1)
1027 {
1028 GRAPH(GetGraph())
1029 {
1030 PARAMETER(0U, 0U).u64();
1031 PARAMETER(1U, 1U).u64();
1032 PARAMETER(2U, 2U).u64();
1033
1034 BASIC_BLOCK(2U, -1L)
1035 {
1036 INST(3U, Opcode::Sub).u64().Inputs(0U, 1U);
1037 INST(4U, Opcode::Sub).u64().Inputs(1U, 2U);
1038 INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
1039 INST(6U, Opcode::Return).u64().Inputs(5U);
1040 }
1041 }
1042 GetGraph()->RunPass<Peepholes>();
1043 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1044 ASSERT_TRUE(CheckInputs(INS(5U), {0U, 2U}));
1045 }
1046
1047 // (a - b) + (c - a) -> c - b
TEST_F(PeepholesTest,AddSubAndSubSameOperandTest2)1048 TEST_F(PeepholesTest, AddSubAndSubSameOperandTest2)
1049 {
1050 GRAPH(GetGraph())
1051 {
1052 PARAMETER(0U, 0U).u64();
1053 PARAMETER(1U, 1U).u64();
1054 PARAMETER(2U, 2U).u64();
1055
1056 BASIC_BLOCK(2U, -1L)
1057 {
1058 INST(3U, Opcode::Sub).u64().Inputs(0U, 1U);
1059 INST(4U, Opcode::Sub).u64().Inputs(2U, 0U);
1060 INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
1061 INST(6U, Opcode::Return).u64().Inputs(5U);
1062 }
1063 }
1064 GetGraph()->RunPass<Peepholes>();
1065 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1066 ASSERT_TRUE(CheckInputs(INS(5U), {2U, 1U}));
1067 }
1068
1069 // a + (0 - b) -> a - b
TEST_F(PeepholesTest,AddSubLeftZeroOperandTest1)1070 TEST_F(PeepholesTest, AddSubLeftZeroOperandTest1)
1071 {
1072 GRAPH(GetGraph())
1073 {
1074 PARAMETER(0U, 0U).u64();
1075 CONSTANT(1U, 0U);
1076 PARAMETER(2U, 1U).u64();
1077
1078 BASIC_BLOCK(2U, -1L)
1079 {
1080 INST(3U, Opcode::Sub).u64().Inputs(1U, 2U);
1081 INST(4U, Opcode::Add).u64().Inputs(0U, 3U);
1082 INST(5U, Opcode::Return).u64().Inputs(4U);
1083 }
1084 }
1085 GetGraph()->RunPass<Peepholes>();
1086 ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Sub);
1087 ASSERT_TRUE(CheckInputs(INS(4U), {0U, 2U}));
1088 }
1089
1090 // (0 - a) + b -> b - a
TEST_F(PeepholesTest,AddSubLeftZeroOperandTest2)1091 TEST_F(PeepholesTest, AddSubLeftZeroOperandTest2)
1092 {
1093 GRAPH(GetGraph())
1094 {
1095 PARAMETER(0U, 0U).u64();
1096 CONSTANT(1U, 0U);
1097 PARAMETER(2U, 1U).u64();
1098
1099 BASIC_BLOCK(2U, -1L)
1100 {
1101 INST(3U, Opcode::Sub).u64().Inputs(1U, 0U);
1102 INST(4U, Opcode::Add).u64().Inputs(3U, 2U);
1103 INST(5U, Opcode::Return).u64().Inputs(4U);
1104 }
1105 }
1106 GetGraph()->RunPass<Peepholes>();
1107 ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Sub);
1108 ASSERT_TRUE(CheckInputs(INS(4U), {2U, 0U}));
1109 }
1110
1111 // (x + a) - (x + b) -> a - b
TEST_F(PeepholesTest,SubAddSameOperandTest1)1112 TEST_F(PeepholesTest, SubAddSameOperandTest1)
1113 {
1114 GRAPH(GetGraph())
1115 {
1116 PARAMETER(0U, 0U).u64();
1117 PARAMETER(1U, 1U).u64();
1118 PARAMETER(2U, 2U).u64();
1119
1120 BASIC_BLOCK(2U, -1L)
1121 {
1122 INST(3U, Opcode::Add).u64().Inputs(0U, 1U);
1123 INST(4U, Opcode::Add).u64().Inputs(0U, 2U);
1124 INST(5U, Opcode::Sub).u64().Inputs(3U, 4U);
1125 INST(6U, Opcode::Return).u64().Inputs(5U);
1126 }
1127 }
1128 GetGraph()->RunPass<Peepholes>();
1129 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1130 ASSERT_TRUE(CheckInputs(INS(5U), {1U, 2U}));
1131 }
1132
1133 // (a + x) - (x + b) -> a - b
TEST_F(PeepholesTest,SubAddSameOperandTest2)1134 TEST_F(PeepholesTest, SubAddSameOperandTest2)
1135 {
1136 GRAPH(GetGraph())
1137 {
1138 PARAMETER(0U, 0U).u64();
1139 PARAMETER(1U, 1U).u64();
1140 PARAMETER(2U, 2U).u64();
1141
1142 BASIC_BLOCK(2U, -1L)
1143 {
1144 INST(3U, Opcode::Add).u64().Inputs(1U, 0U);
1145 INST(4U, Opcode::Add).u64().Inputs(0U, 2U);
1146 INST(5U, Opcode::Sub).u64().Inputs(3U, 4U);
1147 INST(6U, Opcode::Return).u64().Inputs(5U);
1148 }
1149 }
1150 GetGraph()->RunPass<Peepholes>();
1151 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1152 ASSERT_TRUE(CheckInputs(INS(5U), {1U, 2U}));
1153 }
1154
1155 // (a + x) - (b + x) -> a - b
TEST_F(PeepholesTest,SubAddSameOperandTest3)1156 TEST_F(PeepholesTest, SubAddSameOperandTest3)
1157 {
1158 GRAPH(GetGraph())
1159 {
1160 PARAMETER(0U, 0U).u64();
1161 PARAMETER(1U, 1U).u64();
1162 PARAMETER(2U, 2U).u64();
1163
1164 BASIC_BLOCK(2U, -1L)
1165 {
1166 INST(3U, Opcode::Add).u64().Inputs(1U, 0U);
1167 INST(4U, Opcode::Add).u64().Inputs(2U, 0U);
1168 INST(5U, Opcode::Sub).u64().Inputs(3U, 4U);
1169 INST(6U, Opcode::Return).u64().Inputs(5U);
1170 }
1171 }
1172 GetGraph()->RunPass<Peepholes>();
1173 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1174 ASSERT_TRUE(CheckInputs(INS(5U), {1U, 2U}));
1175 }
1176
1177 // (x + a) - (b + x) -> a - b
TEST_F(PeepholesTest,SubAddSameOperandTest4)1178 TEST_F(PeepholesTest, SubAddSameOperandTest4)
1179 {
1180 GRAPH(GetGraph())
1181 {
1182 PARAMETER(0U, 0U).u64();
1183 PARAMETER(1U, 1U).u64();
1184 PARAMETER(2U, 2U).u64();
1185
1186 BASIC_BLOCK(2U, -1L)
1187 {
1188 INST(3U, Opcode::Add).u64().Inputs(0U, 1U);
1189 INST(4U, Opcode::Add).u64().Inputs(2U, 0U);
1190 INST(5U, Opcode::Sub).u64().Inputs(3U, 4U);
1191 INST(6U, Opcode::Return).u64().Inputs(5U);
1192 }
1193 }
1194 GetGraph()->RunPass<Peepholes>();
1195 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1196 ASSERT_TRUE(CheckInputs(INS(5U), {1U, 2U}));
1197 }
1198
TEST_F(PeepholesTest,SubZeroConstantTest)1199 TEST_F(PeepholesTest, SubZeroConstantTest)
1200 {
1201 GRAPH(GetGraph())
1202 {
1203 PARAMETER(0U, 0U).u64();
1204 CONSTANT(3U, 0U);
1205
1206 BASIC_BLOCK(2U, -1L)
1207 {
1208 INST(6U, Opcode::Sub).u64().Inputs(0U, 3U);
1209 INST(20U, Opcode::SaveState).NoVregs();
1210 INST(9U, Opcode::CallStatic).s32().InputsAutoType(6U, 20U);
1211 INST(10U, Opcode::Return).s32().Inputs(9U);
1212 }
1213 }
1214 GetGraph()->RunPass<Peepholes>();
1215
1216 ASSERT_TRUE(INS(6U).GetUsers().Empty());
1217 ASSERT_TRUE(INS(9U).GetInput(0U) == &INS(0U));
1218 }
1219
TEST_F(PeepholesTest,SubFromZeroConstantTest)1220 TEST_F(PeepholesTest, SubFromZeroConstantTest)
1221 {
1222 GRAPH(GetGraph())
1223 {
1224 PARAMETER(0U, 0U).s64();
1225 CONSTANT(1U, 0U);
1226
1227 BASIC_BLOCK(2U, -1L)
1228 {
1229 INST(2U, Opcode::Sub).s64().Inputs(1U, 0U);
1230 INST(3U, Opcode::Return).s64().Inputs(2U);
1231 }
1232 }
1233
1234 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
1235 GetGraph()->RunPass<Cleanup>();
1236 auto graph = CreateEmptyGraph();
1237 GRAPH(graph)
1238 {
1239 PARAMETER(0U, 0U).s64();
1240
1241 BASIC_BLOCK(2U, -1L)
1242 {
1243 INST(2U, Opcode::Neg).s64().Inputs(0U);
1244 INST(3U, Opcode::Return).s64().Inputs(2U);
1245 }
1246 }
1247 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1248 }
1249
TEST_F(PeepholesTest,SubFromZeroConstantFPTest)1250 TEST_F(PeepholesTest, SubFromZeroConstantFPTest)
1251 {
1252 GRAPH(GetGraph())
1253 {
1254 PARAMETER(0U, 0U).f64();
1255 CONSTANT(1U, 0.0);
1256
1257 BASIC_BLOCK(2U, -1L)
1258 {
1259 INST(2U, Opcode::Sub).f64().Inputs(1U, 0U);
1260 INST(3U, Opcode::Return).f64().Inputs(2U);
1261 }
1262 }
1263
1264 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
1265 }
1266
TEST_F(PeepholesTest,SubConstantTest1)1267 TEST_F(PeepholesTest, SubConstantTest1)
1268 {
1269 GRAPH(GetGraph())
1270 {
1271 PARAMETER(0U, 0U).u64();
1272 CONSTANT(1U, 5U);
1273 CONSTANT(2U, 6U);
1274
1275 BASIC_BLOCK(2U, -1L)
1276 {
1277 INST(3U, Opcode::Add).u64().Inputs(0U, 1U);
1278 INST(4U, Opcode::Sub).u64().Inputs(0U, 1U);
1279
1280 INST(5U, Opcode::Sub).u64().Inputs(3U, 2U);
1281 INST(6U, Opcode::Sub).u64().Inputs(4U, 2U);
1282 INST(20U, Opcode::SaveState).NoVregs();
1283 INST(8U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 20U);
1284 INST(7U, Opcode::Return).u64().Inputs(8U);
1285 }
1286 }
1287 GetGraph()->RunPass<Peepholes>();
1288 auto const3 = static_cast<ConstantInst *>(INS(2U).GetNext());
1289 ASSERT_TRUE(const3 != nullptr);
1290 auto const4 = static_cast<ConstantInst *>(const3->GetNext());
1291 ASSERT_TRUE(const4 != nullptr && const4->GetNext() == nullptr);
1292 ASSERT_TRUE(const3->IsEqualConst(1U));
1293 ASSERT_TRUE(const4->IsEqualConst(11U));
1294
1295 ASSERT_TRUE(INS(5U).GetInput(0U) == &INS(0U) && INS(5U).GetInput(1U) == const3);
1296 ASSERT_TRUE(INS(6U).GetInput(0U) == &INS(0U) && INS(6U).GetInput(1U) == const4);
1297
1298 ASSERT_TRUE(CheckUsers(INS(0U), {3U, 4U, 5U, 6U}));
1299 ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U}));
1300 ASSERT_TRUE(INS(2U).GetUsers().Empty());
1301 ASSERT_TRUE(CheckUsers(*const3, {5U}));
1302 ASSERT_TRUE(CheckUsers(*const4, {6U}));
1303 }
1304
TEST_F(PeepholesTest,SubConstantTest2)1305 TEST_F(PeepholesTest, SubConstantTest2)
1306 {
1307 GRAPH(GetGraph())
1308 {
1309 PARAMETER(0U, 0U).u64();
1310 CONSTANT(1U, 5U);
1311 CONSTANT(2U, 6U);
1312
1313 BASIC_BLOCK(2U, -1L)
1314 {
1315 INST(3U, Opcode::Add).u64().Inputs(0U, 1U);
1316 INST(4U, Opcode::Sub).u64().Inputs(0U, 1U);
1317
1318 INST(5U, Opcode::Sub).u32().Inputs(3U, 2U);
1319 INST(6U, Opcode::Sub).u32().Inputs(4U, 2U);
1320 INST(20U, Opcode::SaveState).NoVregs();
1321 INST(8U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 20U);
1322 INST(7U, Opcode::Return).u64().Inputs(8U);
1323 }
1324 }
1325 GetGraph()->RunPass<Peepholes>();
1326
1327 ASSERT_TRUE(INS(2U).GetNext() == nullptr);
1328
1329 ASSERT_TRUE(CheckInputs(INS(3U), {0U, 1U}));
1330 ASSERT_TRUE(CheckInputs(INS(4U), {0U, 1U}));
1331 ASSERT_TRUE(CheckInputs(INS(5U), {3U, 2U}));
1332 ASSERT_TRUE(CheckInputs(INS(6U), {4U, 2U}));
1333
1334 ASSERT_TRUE(CheckUsers(INS(0U), {3U, 4U}));
1335 ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U}));
1336 ASSERT_TRUE(CheckUsers(INS(2U), {5U, 6U}));
1337 ASSERT_TRUE(CheckUsers(INS(3U), {5U}));
1338 ASSERT_TRUE(CheckUsers(INS(4U), {6U}));
1339 }
1340
TEST_F(PeepholesTest,SubNegTest)1341 TEST_F(PeepholesTest, SubNegTest)
1342 {
1343 GRAPH(GetGraph())
1344 {
1345 PARAMETER(0U, 0U).u64();
1346 PARAMETER(1U, 1U).u64();
1347
1348 BASIC_BLOCK(2U, -1L)
1349 {
1350 INST(2U, Opcode::Neg).u64().Inputs(0U);
1351 INST(3U, Opcode::Neg).u64().Inputs(1U);
1352
1353 INST(4U, Opcode::Sub).u64().Inputs(0U, 3U);
1354 INST(5U, Opcode::Sub).u64().Inputs(2U, 0U);
1355 INST(6U, Opcode::Sub).u64().Inputs(2U, 3U);
1356 INST(7U, Opcode::Sub).u64().Inputs(3U, 2U);
1357 INST(20U, Opcode::SaveState).NoVregs();
1358 INST(8U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 6U, 7U, 20U);
1359 INST(9U, Opcode::Return).u64().Inputs(8U);
1360 }
1361 }
1362 GetGraph()->RunPass<Peepholes>();
1363
1364 ASSERT_TRUE(CheckInputs(INS(4U), {0U, 1U}));
1365 ASSERT_TRUE(INS(4U).GetOpcode() == Opcode::Add);
1366 ASSERT_TRUE(CheckInputs(INS(5U), {2U, 0U}));
1367 ASSERT_TRUE(INS(5U).GetOpcode() == Opcode::Sub);
1368 ASSERT_TRUE(CheckInputs(INS(6U), {1U, 0U}));
1369 ASSERT_TRUE(INS(6U).GetOpcode() == Opcode::Sub);
1370 ASSERT_TRUE(CheckInputs(INS(7U), {0U, 1U}));
1371 ASSERT_TRUE(INS(7U).GetOpcode() == Opcode::Sub);
1372 }
1373
TEST_F(PeepholesTest,SameSubAndAddTest1)1374 TEST_F(PeepholesTest, SameSubAndAddTest1)
1375 {
1376 GRAPH(GetGraph())
1377 {
1378 PARAMETER(0U, 0U).u64();
1379 PARAMETER(1U, 1U).u64();
1380
1381 BASIC_BLOCK(2U, -1L)
1382 {
1383 INST(2U, Opcode::Add).u64().Inputs(0U, 1U);
1384
1385 INST(4U, Opcode::Sub).u64().Inputs(2U, 0U);
1386 INST(5U, Opcode::Sub).u64().Inputs(2U, 1U);
1387 INST(6U, Opcode::Add).u64().Inputs(4U, 5U);
1388 INST(7U, Opcode::Return).u64().Inputs(6U);
1389 }
1390 }
1391 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
1392
1393 ASSERT_TRUE(INS(4U).GetUsers().Empty());
1394 ASSERT_TRUE(INS(5U).GetUsers().Empty());
1395 ASSERT_TRUE(CheckInputs(INS(6U), {1U, 0U}));
1396 }
1397
TEST_F(PeepholesTest,SameSubAndAddTest2)1398 TEST_F(PeepholesTest, SameSubAndAddTest2)
1399 {
1400 GRAPH(GetGraph())
1401 {
1402 PARAMETER(0U, 0U).u64();
1403 PARAMETER(1U, 1U).u64();
1404
1405 BASIC_BLOCK(2U, -1L)
1406 {
1407 INST(2U, Opcode::Sub).u64().Inputs(0U, 1U);
1408 INST(3U, Opcode::Sub).u64().Inputs(1U, 0U);
1409
1410 INST(4U, Opcode::Sub).u64().Inputs(0U, 2U);
1411 INST(5U, Opcode::Sub).u64().Inputs(3U, 1U);
1412 INST(6U, Opcode::Add).u64().Inputs(4U, 5U);
1413 INST(7U, Opcode::Return).u64().Inputs(6U);
1414 }
1415 }
1416 GetGraph()->RunPass<Peepholes>();
1417
1418 ASSERT_TRUE(INS(4U).GetUsers().Empty());
1419 ASSERT_TRUE(CheckUsers(INS(5U), {6U}));
1420 ASSERT_TRUE(CheckInputs(INS(6U), {1U, 5U}));
1421 }
1422
TEST_F(PeepholesTest,TestOr2Addition1)1423 TEST_F(PeepholesTest, TestOr2Addition1)
1424 {
1425 // Case 1 + Case 2
1426 GRAPH(GetGraph())
1427 {
1428 PARAMETER(0U, 1U).u64();
1429 CONSTANT(1U, 0U);
1430 BASIC_BLOCK(2U, -1L)
1431 {
1432 INST(2U, Opcode::Or).u64().Inputs(0U, 1U);
1433 INST(3U, Opcode::Return).u64().Inputs(2U);
1434 }
1435 }
1436 GetGraph()->RunPass<Peepholes>();
1437 GraphChecker(GetGraph()).Check();
1438 ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
1439 ASSERT_EQ(INS(1U).GetUsers().Front().GetIndex(), 1U);
1440 ASSERT_EQ(INS(0U).GetUsers().Front().GetIndex(), 0U);
1441 }
1442
TEST_F(PeepholesTest,TestOr3)1443 TEST_F(PeepholesTest, TestOr3)
1444 {
1445 // case 3:
1446 // 1.i64 OR v5, v5
1447 // 2.i64 INS which use v1
1448 // ===>
1449 // 1.i64 OR v5, v5
1450 // 2.i64 INS which use v5
1451 GRAPH(GetGraph())
1452 {
1453 PARAMETER(0U, 1U).u64();
1454 BASIC_BLOCK(2U, -1L)
1455 {
1456 INST(2U, Opcode::Or).u64().Inputs(0U, 0U);
1457 INST(3U, Opcode::Return).u64().Inputs(2U);
1458 }
1459 }
1460 GetGraph()->RunPass<Peepholes>();
1461 GraphChecker(GetGraph()).Check();
1462 ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
1463 }
1464
TEST_F(PeepholesTest,TestOr4)1465 TEST_F(PeepholesTest, TestOr4)
1466 {
1467 // case 4: De Morgan rules
1468 // 2.i64 not v0 -> {4}
1469 // 3.i64 not v1 -> {4}
1470 // 4.i64 OR v2, v3
1471 // ===>
1472 // 5.i64 AND v0, v1
1473 // 6.i64 not v5
1474 GRAPH(GetGraph())
1475 {
1476 PARAMETER(0U, 1U).u64();
1477 PARAMETER(1U, 2U).u64();
1478 BASIC_BLOCK(2U, -1L)
1479 {
1480 INST(2U, Opcode::Not).u64().Inputs(0U);
1481 INST(3U, Opcode::Not).u64().Inputs(1U);
1482 INST(4U, Opcode::Or).u64().Inputs(2U, 3U);
1483 INST(5U, Opcode::Return).u64().Inputs(4U);
1484 }
1485 }
1486 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
1487 GraphChecker(GetGraph()).Check();
1488 auto notInst = INS(5U).GetInput(0U).GetInst();
1489 ASSERT_EQ(notInst->GetOpcode(), Opcode::Not);
1490 auto andInst = notInst->GetInput(0U).GetInst();
1491 ASSERT_EQ(andInst->GetOpcode(), Opcode::And);
1492 ASSERT_EQ(andInst->GetInput(0U).GetInst(), &INS(0U));
1493 ASSERT_EQ(andInst->GetInput(1U).GetInst(), &INS(1U));
1494 }
1495
TEST_F(PeepholesTest,TestOr4Addition1)1496 TEST_F(PeepholesTest, TestOr4Addition1)
1497 {
1498 // Case 4, but NOT-inst have more than 1 user
1499 GRAPH(GetGraph())
1500 {
1501 PARAMETER(0U, 1U).u64();
1502 PARAMETER(1U, 2U).u64();
1503 BASIC_BLOCK(2U, -1L)
1504 {
1505 INST(2U, Opcode::Not).u64().Inputs(0U);
1506 INST(3U, Opcode::Not).u64().Inputs(1U);
1507 INST(4U, Opcode::Or).u64().Inputs(2U, 3U);
1508 INST(5U, Opcode::Not).u64().Inputs(2U);
1509 INST(6U, Opcode::Not).u64().Inputs(3U);
1510 INST(20U, Opcode::SaveState).NoVregs();
1511 INST(8U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 6U, 20U);
1512 INST(7U, Opcode::Return).u64().Inputs(8U);
1513 }
1514 }
1515 GetGraph()->RunPass<Peepholes>();
1516 GraphChecker(GetGraph()).Check();
1517 auto orInst = INS(8U).GetInput(0U).GetInst();
1518 ASSERT_EQ(orInst->GetOpcode(), Opcode::Or);
1519 }
1520
TEST_F(PeepholesTest,NegTest1)1521 TEST_F(PeepholesTest, NegTest1)
1522 {
1523 GRAPH(GetGraph())
1524 {
1525 PARAMETER(0U, 0U).s64();
1526 PARAMETER(1U, 1U).s64();
1527 BASIC_BLOCK(2U, -1L)
1528 {
1529 INST(4U, Opcode::Neg).s64().Inputs(0U);
1530 INST(5U, Opcode::Neg).s64().Inputs(4U);
1531 INST(6U, Opcode::Add).s64().Inputs(1U, 5U);
1532 INST(20U, Opcode::SaveState).NoVregs();
1533 INST(11U, Opcode::CallStatic).u32().InputsAutoType(6U, 20U);
1534 INST(10U, Opcode::Return).u32().Inputs(11U);
1535 }
1536 }
1537 GetGraph()->RunPass<Peepholes>();
1538
1539 ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
1540 ASSERT_TRUE(INS(5U).GetUsers().Empty());
1541 ASSERT_TRUE(CheckInputs(INS(6U), {1U, 0U}));
1542 ASSERT_EQ(INS(6U).GetOpcode(), Opcode::Add);
1543 }
1544
TEST_F(PeepholesTest,NegTest2)1545 TEST_F(PeepholesTest, NegTest2)
1546 {
1547 GRAPH(GetGraph())
1548 {
1549 PARAMETER(0U, 0U).s64();
1550 PARAMETER(1U, 1U).s64();
1551 BASIC_BLOCK(2U, -1L)
1552 {
1553 INST(2U, Opcode::Sub).s64().Inputs(0U, 1U);
1554 INST(3U, Opcode::Neg).s64().Inputs(2U);
1555 INST(4U, Opcode::Return).s64().Inputs(3U);
1556 }
1557 }
1558 GetGraph()->RunPass<Peepholes>();
1559
1560 ASSERT_TRUE(INS(3U).GetUsers().Empty());
1561 ASSERT_NE(INS(3U).GetNext(), &INS(4U));
1562 auto sub = INS(3U).GetNext();
1563 ASSERT_EQ(sub->GetOpcode(), Opcode::Sub);
1564 ASSERT_EQ(sub->GetType(), INS(3U).GetType());
1565
1566 ASSERT_EQ(sub->GetInput(0U).GetInst(), &INS(1U));
1567 ASSERT_EQ(sub->GetInput(1U).GetInst(), &INS(0U));
1568
1569 ASSERT_EQ(INS(4U).GetInput(0U).GetInst(), sub);
1570 }
1571
SRC_GRAPH(NegationCompare,Graph * graph)1572 SRC_GRAPH(NegationCompare, Graph *graph)
1573 {
1574 GRAPH(graph)
1575 {
1576 PARAMETER(0U, 0U).s64();
1577 PARAMETER(1U, 1U).s64();
1578 CONSTANT(5U, 0x1U);
1579 BASIC_BLOCK(2U, -1L)
1580 {
1581 INST(2U, Opcode::Compare).b().CC(CC_GT).Inputs(0U, 1U);
1582 INST(3U, Opcode::Neg).s32().Inputs(2U);
1583 INST(6U, Opcode::Add).s32().Inputs(3U, 5U);
1584 INST(4U, Opcode::Return).b().Inputs(6U);
1585 }
1586 }
1587 }
1588
OUT_GRAPH(NegationCompare,Graph * graph)1589 OUT_GRAPH(NegationCompare, Graph *graph)
1590 {
1591 GRAPH(graph)
1592 {
1593 PARAMETER(0U, 0U).s64();
1594 PARAMETER(1U, 1U).s64();
1595 BASIC_BLOCK(2U, -1L)
1596 {
1597 INST(2U, Opcode::Compare).b().CC(CC_LE).Inputs(0U, 1U);
1598 INST(4U, Opcode::Return).b().Inputs(2U);
1599 }
1600 }
1601 }
1602
SRC_GRAPH(NegationCompareOSR,Graph * graph)1603 SRC_GRAPH(NegationCompareOSR, Graph *graph)
1604 {
1605 GRAPH(graph)
1606 {
1607 PARAMETER(0U, 0U).s64();
1608 PARAMETER(1U, 1U).s64();
1609 CONSTANT(5U, 0x1U);
1610 BASIC_BLOCK(2U, 3U)
1611 {
1612 INST(2U, Opcode::Compare).b().CC(CC_GT).Inputs(0U, 1U);
1613 INST(3U, Opcode::Neg).s32().Inputs(2U);
1614 INST(6U, Opcode::Add).s32().Inputs(3U, 5U);
1615 }
1616 BASIC_BLOCK(3U, -1L)
1617 {
1618 INST(4U, Opcode::Return).b().Inputs(6U);
1619 }
1620 }
1621 }
1622
OUT_GRAPH(NegationCompareOSR,Graph * graph)1623 OUT_GRAPH(NegationCompareOSR, Graph *graph)
1624 {
1625 GRAPH(graph)
1626 {
1627 PARAMETER(0U, 0U).s64();
1628 PARAMETER(1U, 1U).s64();
1629 CONSTANT(5U, 0x1U);
1630 BASIC_BLOCK(2U, 3U)
1631 {
1632 INST(2U, Opcode::Compare).b().CC(CC_LE).Inputs(0U, 1U);
1633 INST(3U, Opcode::Neg).s32().Inputs(2U);
1634 INST(6U, Opcode::Add).s32().Inputs(3U, 5U);
1635 }
1636 BASIC_BLOCK(3U, -1L)
1637 {
1638 INST(4U, Opcode::Return).b().Inputs(2U);
1639 }
1640 }
1641 }
1642
TEST_F(PeepholesTest,NegationCompare)1643 TEST_F(PeepholesTest, NegationCompare)
1644 {
1645 src_graph::NegationCompare::CREATE(GetGraph());
1646 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
1647 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1648
1649 auto graph = CreateEmptyGraph();
1650 out_graph::NegationCompare::CREATE(graph);
1651 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1652
1653 // Test with OSR
1654 auto defaultGraph = CreateEmptyGraph();
1655 src_graph::NegationCompareOSR::CREATE(defaultGraph);
1656 Graph *graphOsr =
1657 GraphCloner(defaultGraph, defaultGraph->GetAllocator(), defaultGraph->GetLocalAllocator()).CloneGraph();
1658 graphOsr->SetMode(GraphMode::Osr());
1659
1660 Graph *graphClone = GraphCloner(graphOsr, graphOsr->GetAllocator(), graphOsr->GetLocalAllocator()).CloneGraph();
1661
1662 ASSERT_FALSE(graphOsr->RunPass<Peepholes>());
1663 ASSERT_TRUE(GraphComparator().Compare(graphOsr, graphClone));
1664
1665 auto optimizedGraph = CreateEmptyGraph();
1666 out_graph::NegationCompareOSR::CREATE(optimizedGraph);
1667 ASSERT_TRUE(defaultGraph->RunPass<Peepholes>());
1668 ASSERT_TRUE(GraphComparator().Compare(defaultGraph, optimizedGraph));
1669 }
1670
SRC_GRAPH(TransformNegationToCompare,Graph * graph)1671 SRC_GRAPH(TransformNegationToCompare, Graph *graph)
1672 {
1673 GRAPH(graph)
1674 {
1675 PARAMETER(0U, 0U).s64();
1676 CONSTANT(5U, 0x1U);
1677 BASIC_BLOCK(2U, 3U)
1678 {
1679 INST(1U, Opcode::SaveState).NoVregs();
1680 INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
1681 INST(3U, Opcode::Neg).s32().Inputs(2U);
1682 INST(6U, Opcode::Add).s32().Inputs(3U, 5U);
1683 }
1684 BASIC_BLOCK(3U, -1L)
1685 {
1686 INST(4U, Opcode::Return).b().Inputs(6U);
1687 }
1688 }
1689 }
1690
OUT_GRAPH(TransformNegationToCompare,Graph * graph)1691 OUT_GRAPH(TransformNegationToCompare, Graph *graph)
1692 {
1693 GRAPH(graph)
1694 {
1695 PARAMETER(0U, 0U).s64();
1696 CONSTANT(5U, 0x1U);
1697 CONSTANT(7U, 0x0U);
1698 BASIC_BLOCK(2U, 3U)
1699 {
1700 INST(1U, Opcode::SaveState).NoVregs();
1701 INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
1702 INST(3U, Opcode::Neg).s32().Inputs(2U);
1703 INST(6U, Opcode::Add).s32().Inputs(3U, 5U);
1704 INST(8U, Opcode::Compare).b().Inputs(2U, 7U);
1705 }
1706 BASIC_BLOCK(3U, -1L)
1707 {
1708 INST(4U, Opcode::Return).b().Inputs(8U);
1709 }
1710 }
1711 }
1712
TEST_F(PeepholesTest,TransformNegationToCompare)1713 TEST_F(PeepholesTest, TransformNegationToCompare)
1714 {
1715 // Test with OSR
1716 auto defaultGraph = CreateEmptyGraph();
1717 src_graph::TransformNegationToCompare::CREATE(defaultGraph);
1718 Graph *graphOsr =
1719 GraphCloner(defaultGraph, defaultGraph->GetAllocator(), defaultGraph->GetLocalAllocator()).CloneGraph();
1720 graphOsr->SetMode(GraphMode::Osr());
1721
1722 Graph *graphClone = GraphCloner(graphOsr, graphOsr->GetAllocator(), graphOsr->GetLocalAllocator()).CloneGraph();
1723
1724 ASSERT_FALSE(graphOsr->RunPass<Peepholes>());
1725 ASSERT_TRUE(GraphComparator().Compare(graphOsr, graphClone));
1726 // Test without OSR
1727 auto optimizedGraph = CreateEmptyGraph();
1728 out_graph::TransformNegationToCompare::CREATE(optimizedGraph);
1729 ASSERT_TRUE(defaultGraph->RunPass<Peepholes>());
1730 ASSERT_TRUE(GraphComparator().Compare(defaultGraph, optimizedGraph));
1731 }
1732
TEST_F(PeepholesTest,NegCompareNotWork)1733 TEST_F(PeepholesTest, NegCompareNotWork)
1734 {
1735 GRAPH(GetGraph())
1736 {
1737 PARAMETER(0U, 0U).s64();
1738 PARAMETER(1U, 1U).s64();
1739 BASIC_BLOCK(2U, -1L)
1740 {
1741 INST(2U, Opcode::Compare).b().CC(CC_GT).Inputs(0U, 1U);
1742 INST(3U, Opcode::Neg).b().Inputs(2U);
1743 INST(5U, Opcode::Mul).b().Inputs(2U, 3U);
1744 INST(4U, Opcode::Return).b().Inputs(5U);
1745 }
1746 }
1747 Graph *graphClone =
1748 GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1749 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
1750 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphClone));
1751 }
1752
SRC_GRAPH(CompareNegation,Graph * graph)1753 SRC_GRAPH(CompareNegation, Graph *graph)
1754 {
1755 GRAPH(graph)
1756 {
1757 PARAMETER(0U, 0U).b();
1758 PARAMETER(1U, 1U).b();
1759 CONSTANT(8U, 0x1U);
1760 BASIC_BLOCK(2U, -1L)
1761 {
1762 INST(2U, Opcode::Neg).i32().Inputs(0U);
1763 INST(9U, Opcode::Add).i32().Inputs(2U, 8U);
1764 INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).SrcType(DataType::BOOL).Inputs(1U, 9U);
1765 INST(7U, Opcode::Return).b().Inputs(4U);
1766 }
1767 }
1768 }
1769
OUT_GRAPH(CompareNegation,Graph * graph)1770 OUT_GRAPH(CompareNegation, Graph *graph)
1771 {
1772 GRAPH(graph)
1773 {
1774 PARAMETER(0U, 0U).b();
1775 PARAMETER(1U, 1U).b();
1776 BASIC_BLOCK(2U, -1L)
1777 {
1778 INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_NE).SrcType(DataType::BOOL).Inputs(1U, 0U);
1779 INST(7U, Opcode::Return).b().Inputs(4U);
1780 }
1781 }
1782 }
1783
TEST_F(PeepholesTest,CompareNegation)1784 TEST_F(PeepholesTest, CompareNegation)
1785 {
1786 src_graph::CompareNegation::CREATE(GetGraph());
1787 auto graph = CreateEmptyGraph();
1788 out_graph::CompareNegation::CREATE(graph);
1789 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
1790 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1791 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1792
1793 auto graph1 = CreateEmptyGraph();
1794 GRAPH(graph1)
1795 {
1796 PARAMETER(0U, 0U).b();
1797 PARAMETER(1U, 1U).b();
1798 CONSTANT(8U, 0x1U);
1799 BASIC_BLOCK(2U, -1L)
1800 {
1801 INST(2U, Opcode::Neg).i32().Inputs(0U);
1802 INST(9U, Opcode::Add).i32().Inputs(2U, 8U);
1803 INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).SrcType(DataType::BOOL).Inputs(1U, 9U);
1804 INST(11U, Opcode::Add).i32().Inputs(4U, 9U);
1805 INST(7U, Opcode::Return).b().Inputs(11U);
1806 }
1807 }
1808 auto graph2 = CreateEmptyGraph();
1809 GRAPH(graph2)
1810 {
1811 PARAMETER(0U, 0U).b();
1812 PARAMETER(1U, 1U).b();
1813 CONSTANT(8U, 0x1U);
1814 BASIC_BLOCK(2U, -1L)
1815 {
1816 INST(2U, Opcode::Neg).i32().Inputs(0U);
1817 INST(9U, Opcode::Add).i32().Inputs(2U, 8U);
1818 INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_NE).SrcType(DataType::BOOL).Inputs(1U, 0U);
1819 INST(11U, Opcode::Add).i32().Inputs(4U, 9U);
1820 INST(7U, Opcode::Return).b().Inputs(11U);
1821 }
1822 }
1823 GraphChecker(graph1).Check();
1824 ASSERT_TRUE(graph1->RunPass<Peepholes>());
1825 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
1826 }
1827
SRC_GRAPH(CompareNegationBoolOsr,Graph * graph)1828 SRC_GRAPH(CompareNegationBoolOsr, Graph *graph)
1829 {
1830 GRAPH(graph)
1831 {
1832 PARAMETER(1U, 1U).b();
1833 CONSTANT(3U, 0x1U);
1834 BASIC_BLOCK(2U, 3U)
1835 {
1836 INST(6U, Opcode::SaveState).NoVregs();
1837 INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
1838 }
1839 BASIC_BLOCK(3U, -1L)
1840 {
1841 INST(2U, Opcode::Neg).s32().Inputs(7U);
1842 INST(8U, Opcode::Add).s32().Inputs(2U, 3U);
1843 INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).SrcType(DataType::BOOL).Inputs(8U, 1U);
1844 INST(5U, Opcode::Return).b().Inputs(4U);
1845 }
1846 }
1847 }
1848
OUT_GRAPH(CompareNegationBoolOsr,Graph * graph)1849 OUT_GRAPH(CompareNegationBoolOsr, Graph *graph)
1850 {
1851 GRAPH(graph)
1852 {
1853 PARAMETER(1U, 1U).b();
1854 CONSTANT(3U, 0x1U);
1855 BASIC_BLOCK(2U, -1L)
1856 {
1857 INST(6U, Opcode::SaveState).NoVregs();
1858 INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
1859
1860 INST(2U, Opcode::Neg).s32().Inputs(7U);
1861 INST(8U, Opcode::Add).s32().Inputs(2U, 3U);
1862 INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).SrcType(DataType::BOOL).Inputs(8U, 1U);
1863 INST(5U, Opcode::Return).b().Inputs(4U);
1864 }
1865 }
1866 }
1867
TEST_F(PeepholesTest,CompareNegationBoolOsr)1868 TEST_F(PeepholesTest, CompareNegationBoolOsr)
1869 {
1870 // Peephole don't work with that graph in OSR
1871 GetGraph()->SetMode(GraphMode::Osr());
1872 src_graph::CompareNegationBoolOsr::CREATE(GetGraph());
1873 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
1874
1875 // Work with that graph
1876 auto optimizableGraph = CreateEmptyGraph();
1877 optimizableGraph->SetMode(GraphMode::Osr());
1878 out_graph::CompareNegationBoolOsr::CREATE(optimizableGraph);
1879
1880 auto optimizableGraphAfter = CreateEmptyGraph();
1881 optimizableGraphAfter->SetMode(GraphMode::Osr());
1882 GRAPH(optimizableGraphAfter)
1883 {
1884 PARAMETER(1U, 1U).b();
1885 BASIC_BLOCK(2U, -1L)
1886 {
1887 INST(6U, Opcode::SaveState).NoVregs();
1888 INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
1889
1890 INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_NE).SrcType(DataType::BOOL).Inputs(7U, 1U);
1891 INST(5U, Opcode::Return).b().Inputs(4U);
1892 }
1893 }
1894 ASSERT_TRUE(optimizableGraph->RunPass<Peepholes>());
1895 ASSERT_TRUE(optimizableGraph->RunPass<Cleanup>());
1896 ASSERT_TRUE(GraphComparator().Compare(optimizableGraph, optimizableGraphAfter));
1897 }
1898
SRC_GRAPH(IfImmNegation,Graph * graph,ConditionCode code)1899 SRC_GRAPH(IfImmNegation, Graph *graph, ConditionCode code)
1900 {
1901 GRAPH(graph)
1902 {
1903 PARAMETER(0U, 0U).b();
1904 PARAMETER(1U, 1U).b();
1905 CONSTANT(8U, 0x1U);
1906 BASIC_BLOCK(2U, 3U, 4U)
1907 {
1908 INST(2U, Opcode::Neg).b().Inputs(0U);
1909 INST(9U, Opcode::Add).i32().Inputs(2U, 8U);
1910 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).Imm(1U).CC(code).Inputs(9U);
1911 }
1912 BASIC_BLOCK(3U, -1L)
1913 {
1914 INST(6U, Opcode::Return).b().Inputs(0U);
1915 }
1916 BASIC_BLOCK(4U, -1L)
1917 {
1918 INST(7U, Opcode::Return).b().Inputs(0U);
1919 }
1920 }
1921 }
1922
OUT_GRAPH(IfImmNegation,Graph * graph,ConditionCode code)1923 OUT_GRAPH(IfImmNegation, Graph *graph, ConditionCode code)
1924 {
1925 GRAPH(graph)
1926 {
1927 PARAMETER(0U, 0U).b();
1928 PARAMETER(1U, 1U).b();
1929 CONSTANT(8U, 0x1U);
1930 CONSTANT(10U, 0x0U);
1931 BASIC_BLOCK(2U, 3U, 4U)
1932 {
1933 INST(2U, Opcode::Neg).b().Inputs(0U);
1934 INST(9U, Opcode::Add).i32().Inputs(2U, 8U);
1935 INST(11U, Opcode::Compare).b().SrcType(DataType::BOOL).Inputs(0U, 10U);
1936 // That optimized by combination Compare + IfImm
1937 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).Imm(1U).CC(GetInverseConditionCode(code)).Inputs(0U);
1938 }
1939 BASIC_BLOCK(3U, -1L)
1940 {
1941 INST(6U, Opcode::Return).b().Inputs(0U);
1942 }
1943 BASIC_BLOCK(4U, -1L)
1944 {
1945 INST(7U, Opcode::Return).b().Inputs(0U);
1946 }
1947 }
1948 }
1949
TEST_F(PeepholesTest,IfImmNegation)1950 TEST_F(PeepholesTest, IfImmNegation)
1951 {
1952 // ConditionCode in IfImm with bool src maybe not only CC_EQ or CC_NE
1953 std::array<ConditionCode, 4U> codes {ConditionCode::CC_NE, ConditionCode::CC_EQ, ConditionCode::CC_GE,
1954 ConditionCode::CC_B};
1955 for (auto code : codes) {
1956 auto graph = CreateEmptyGraph();
1957 src_graph::IfImmNegation::CREATE(graph, code);
1958
1959 Graph *finalGraph = nullptr;
1960 finalGraph = CreateEmptyGraph();
1961 out_graph::IfImmNegation::CREATE(finalGraph, code);
1962 ASSERT_TRUE(graph->RunPass<Peepholes>());
1963 ASSERT_TRUE(GraphComparator().Compare(graph, finalGraph));
1964 }
1965 }
1966
SRC_GRAPH(IfImmNegationOsr,Graph * graph)1967 SRC_GRAPH(IfImmNegationOsr, Graph *graph)
1968 {
1969 GRAPH(graph)
1970 {
1971 PARAMETER(0U, 0U).b();
1972 PARAMETER(1U, 1U).b();
1973 CONSTANT(3U, 0x1U);
1974 BASIC_BLOCK(2U, 3U)
1975 {
1976 INST(6U, Opcode::SaveState).NoVregs();
1977 INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
1978 }
1979 BASIC_BLOCK(3U, 4U, 5U)
1980 {
1981 INST(2U, Opcode::Neg).s32().Inputs(7U);
1982 INST(9U, Opcode::Add).s32().Inputs(2U, 3U);
1983 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).Imm(1U).CC(ConditionCode::CC_EQ).Inputs(9U);
1984 }
1985 BASIC_BLOCK(4U, -1L)
1986 {
1987 INST(5U, Opcode::Return).b().Inputs(0U);
1988 }
1989 BASIC_BLOCK(5U, -1L)
1990 {
1991 INST(8U, Opcode::Return).b().Inputs(0U);
1992 }
1993 }
1994 }
1995
OUT_GRAPH(IfImmNegationOsr,Graph * graph)1996 OUT_GRAPH(IfImmNegationOsr, Graph *graph)
1997 {
1998 GRAPH(graph)
1999 {
2000 PARAMETER(0U, 0U).b();
2001 PARAMETER(1U, 1U).b();
2002 CONSTANT(3U, 0x1U);
2003 BASIC_BLOCK(2U, 4U, 5U)
2004 {
2005 INST(6U, Opcode::SaveState).NoVregs();
2006 INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
2007
2008 INST(2U, Opcode::Neg).s32().Inputs(7U);
2009 INST(9U, Opcode::Add).s32().Inputs(2U, 3U);
2010 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).Imm(1U).CC(ConditionCode::CC_EQ).Inputs(9U);
2011 }
2012 BASIC_BLOCK(4U, -1L)
2013 {
2014 INST(5U, Opcode::Return).b().Inputs(0U);
2015 }
2016 BASIC_BLOCK(5U, -1L)
2017 {
2018 INST(8U, Opcode::Return).b().Inputs(0U);
2019 }
2020 }
2021 }
2022
TEST_F(PeepholesTest,IfImmNegationOsr)2023 TEST_F(PeepholesTest, IfImmNegationOsr)
2024 {
2025 // Peephole don't work with that graph in OSR
2026 GetGraph()->SetMode(GraphMode::Osr());
2027 src_graph::IfImmNegationOsr::CREATE(GetGraph());
2028 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
2029
2030 // Work with that graph
2031 auto optimizableGraph = CreateEmptyGraph();
2032 optimizableGraph->SetMode(GraphMode::Osr());
2033 out_graph::IfImmNegationOsr::CREATE(optimizableGraph);
2034
2035 auto optimizableGraphAfter = CreateEmptyGraph();
2036 optimizableGraphAfter->SetMode(GraphMode::Osr());
2037 GRAPH(optimizableGraphAfter)
2038 {
2039 PARAMETER(0U, 0U).b();
2040 PARAMETER(1U, 1U).b();
2041 CONSTANT(3U, 0x1U);
2042 CONSTANT(10U, 0x0U);
2043 BASIC_BLOCK(2U, 4U, 5U)
2044 {
2045 INST(6U, Opcode::SaveState).NoVregs();
2046 INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
2047
2048 INST(2U, Opcode::Neg).s32().Inputs(7U);
2049 INST(9U, Opcode::Add).s32().Inputs(2U, 3U);
2050 INST(11U, Opcode::Compare).b().SrcType(DataType::BOOL).Inputs(7U, 10U);
2051 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).Imm(1U).CC(ConditionCode::CC_NE).Inputs(7U);
2052 }
2053 BASIC_BLOCK(4U, -1L)
2054 {
2055 INST(5U, Opcode::Return).b().Inputs(0U);
2056 }
2057 BASIC_BLOCK(5U, -1L)
2058 {
2059 INST(8U, Opcode::Return).b().Inputs(0U);
2060 }
2061 }
2062 ASSERT_TRUE(optimizableGraph->RunPass<Peepholes>());
2063 ASSERT_TRUE(GraphComparator().Compare(optimizableGraph, optimizableGraphAfter));
2064 }
2065
2066 // Checking the shift with zero constant
TEST_F(PeepholesTest,ShlZeroTest)2067 TEST_F(PeepholesTest, ShlZeroTest)
2068 {
2069 GRAPH(GetGraph())
2070 {
2071 PARAMETER(0U, 0U).u64();
2072 CONSTANT(1U, 0U);
2073 CONSTANT(2U, 1U);
2074
2075 BASIC_BLOCK(2U, -1L)
2076 {
2077 INST(3U, Opcode::Shl).u64().Inputs(0U, 1U);
2078 INST(4U, Opcode::Shl).u64().Inputs(0U, 2U);
2079
2080 INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
2081 INST(6U, Opcode::Return).u64().Inputs(5U);
2082 }
2083 }
2084 GetGraph()->RunPass<Peepholes>();
2085
2086 ASSERT_TRUE(INS(3U).GetUsers().Empty());
2087
2088 ASSERT_TRUE(CheckInputs(INS(5U), {0U, 4U}));
2089 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
2090 }
2091
2092 // Checking repeated shifts for constants with the same types
TEST_F(PeepholesTest,ShlRepeatConstTest1)2093 TEST_F(PeepholesTest, ShlRepeatConstTest1)
2094 {
2095 GRAPH(GetGraph())
2096 {
2097 PARAMETER(0U, 0U).u64();
2098 CONSTANT(1U, 5U);
2099 CONSTANT(2U, 6U);
2100
2101 BASIC_BLOCK(2U, -1L)
2102 {
2103 INST(3U, Opcode::Shl).u64().Inputs(0U, 1U);
2104 INST(4U, Opcode::Shl).u64().Inputs(3U, 2U);
2105 INST(5U, Opcode::Return).u64().Inputs(4U);
2106 }
2107 }
2108 GetGraph()->RunPass<Peepholes>();
2109
2110 ASSERT_NE(INS(2U).GetNext(), nullptr);
2111 auto const3 = static_cast<ConstantInst *>(INS(2U).GetNext());
2112 ASSERT_TRUE(const3->IsEqualConst(11U));
2113
2114 ASSERT_TRUE(INS(3U).GetUsers().Empty());
2115 ASSERT_EQ(INS(3U).GetOpcode(), Opcode::Shl);
2116 ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2117 ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Shl);
2118 ASSERT_EQ(INS(4U).GetInput(0U).GetInst(), &INS(0U));
2119 ASSERT_EQ(INS(4U).GetInput(1U).GetInst(), const3);
2120
2121 ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2122 }
2123
2124 // Checking repeated shifts for constants with different types
TEST_F(PeepholesTest,ShlRepeatConstTest2)2125 TEST_F(PeepholesTest, ShlRepeatConstTest2)
2126 {
2127 GRAPH(GetGraph())
2128 {
2129 PARAMETER(0U, 0U).u32();
2130 CONSTANT(1U, 5U);
2131 CONSTANT(2U, 6U);
2132
2133 BASIC_BLOCK(2U, -1L)
2134 {
2135 INST(3U, Opcode::Shl).u16().Inputs(0U, 1U);
2136 INST(4U, Opcode::Shl).u32().Inputs(3U, 2U);
2137 INST(5U, Opcode::Return).u32().Inputs(4U);
2138 }
2139 }
2140 GetGraph()->RunPass<Peepholes>();
2141
2142 ASSERT_EQ(INS(2U).GetNext(), nullptr);
2143
2144 ASSERT_TRUE(CheckInputs(INS(3U), {0U, 1U}));
2145 ASSERT_TRUE(CheckUsers(INS(3U), {4U}));
2146 ASSERT_EQ(INS(3U).GetOpcode(), Opcode::Shl);
2147 ASSERT_TRUE(CheckInputs(INS(4U), {3U, 2U}));
2148 ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2149 ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Shl);
2150
2151 ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2152 }
2153
2154 // Checking the shift for a constant greater than the type size
SRC_GRAPH(ShlBigConstTest,Graph * graph)2155 SRC_GRAPH(ShlBigConstTest, Graph *graph)
2156 {
2157 GRAPH(graph)
2158 {
2159 PARAMETER(0U, 0U).u64();
2160 PARAMETER(1U, 1U).u32();
2161 PARAMETER(2U, 2U).u16();
2162 PARAMETER(3U, 3U).u8();
2163 CONSTANT(4U, 127U);
2164
2165 BASIC_BLOCK(2U, -1L)
2166 {
2167 INST(5U, Opcode::Shl).u64().Inputs(0U, 4U);
2168 INST(6U, Opcode::Shl).u32().Inputs(1U, 4U);
2169 INST(7U, Opcode::Shl).u16().Inputs(2U, 4U);
2170 INST(8U, Opcode::Shl).u8().Inputs(3U, 4U);
2171 INST(20U, Opcode::SaveState).NoVregs();
2172 INST(10U, Opcode::CallStatic).s64().InputsAutoType(5U, 6U, 7U, 8U, 20U);
2173 INST(9U, Opcode::Return).s64().Inputs(10U);
2174 }
2175 }
2176 }
2177
TEST_F(PeepholesTest,ShlBigConstTest)2178 TEST_F(PeepholesTest, ShlBigConstTest)
2179 {
2180 src_graph::ShlBigConstTest::CREATE(GetGraph());
2181 GetGraph()->RunPass<Peepholes>();
2182
2183 ASSERT_NE(INS(4U).GetNext(), nullptr);
2184 auto const64 = static_cast<ConstantInst *>(INS(4U).GetNext());
2185 ASSERT_TRUE(const64->IsEqualConst(63U));
2186
2187 ASSERT_NE(const64->GetNext(), nullptr);
2188 auto const32 = static_cast<ConstantInst *>(const64->GetNext());
2189 ASSERT_TRUE(const32->IsEqualConst(31U));
2190
2191 ASSERT_NE(const32->GetNext(), nullptr);
2192 auto const16 = static_cast<ConstantInst *>(const32->GetNext());
2193 ASSERT_TRUE(const16->IsEqualConst(15U));
2194
2195 ASSERT_NE(const16->GetNext(), nullptr);
2196 auto const8 = static_cast<ConstantInst *>(const16->GetNext());
2197 ASSERT_TRUE(const8->IsEqualConst(7U));
2198
2199 ASSERT_EQ(INS(5U).GetInput(0U).GetInst(), &INS(0U));
2200 ASSERT_EQ(INS(5U).GetInput(1U).GetInst(), const64);
2201 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Shl);
2202
2203 ASSERT_EQ(INS(6U).GetInput(0U).GetInst(), &INS(1U));
2204 ASSERT_EQ(INS(6U).GetInput(1U).GetInst(), const32);
2205 ASSERT_EQ(INS(6U).GetOpcode(), Opcode::Shl);
2206
2207 ASSERT_EQ(INS(7U).GetInput(0U).GetInst(), &INS(2U));
2208 ASSERT_EQ(INS(7U).GetInput(1U).GetInst(), const16);
2209 ASSERT_EQ(INS(7U).GetOpcode(), Opcode::Shl);
2210
2211 ASSERT_EQ(INS(8U).GetInput(0U).GetInst(), &INS(3U));
2212 ASSERT_EQ(INS(8U).GetInput(1U).GetInst(), const8);
2213 ASSERT_EQ(INS(8U).GetOpcode(), Opcode::Shl);
2214 }
2215
TEST_F(PeepholesTest,ShlPlusShrTest)2216 TEST_F(PeepholesTest, ShlPlusShrTest)
2217 {
2218 // applied
2219 GRAPH(GetGraph())
2220 {
2221 PARAMETER(0U, 0U).s32();
2222 CONSTANT(1U, 0x18U);
2223
2224 BASIC_BLOCK(2U, -1L)
2225 {
2226 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2227 INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
2228 INST(4U, Opcode::Return).s32().Inputs(3U);
2229 }
2230 }
2231 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2232 GetGraph()->RunPass<Cleanup>();
2233 auto graph = CreateEmptyGraph();
2234 GRAPH(graph)
2235 {
2236 PARAMETER(0U, 0U).s32();
2237 CONSTANT(5U, 0xffU);
2238
2239 BASIC_BLOCK(2U, -1L)
2240 {
2241 INST(6U, Opcode::And).s32().Inputs(0U, 5U);
2242 INST(4U, Opcode::Return).s32().Inputs(6U);
2243 }
2244 }
2245 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2246 }
2247
TEST_F(PeepholesTest,ShlPlusShrTest1)2248 TEST_F(PeepholesTest, ShlPlusShrTest1)
2249 {
2250 // not applied, different constants
2251 GRAPH(GetGraph())
2252 {
2253 PARAMETER(0U, 0U).s32();
2254 CONSTANT(1U, 0x18U);
2255 CONSTANT(5U, 0x10U);
2256
2257 BASIC_BLOCK(2U, -1L)
2258 {
2259 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2260 INST(3U, Opcode::Shr).s32().Inputs(2U, 5U);
2261 INST(4U, Opcode::Return).s32().Inputs(3U);
2262 }
2263 }
2264 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
2265 auto graph = CreateEmptyGraph();
2266 GRAPH(graph)
2267 {
2268 PARAMETER(0U, 0U).s32();
2269 CONSTANT(1U, 0x18U);
2270 CONSTANT(5U, 0x10U);
2271
2272 BASIC_BLOCK(2U, -1L)
2273 {
2274 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2275 INST(3U, Opcode::Shr).s32().Inputs(2U, 5U);
2276 INST(4U, Opcode::Return).s32().Inputs(3U);
2277 }
2278 }
2279 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2280 }
2281
TEST_F(PeepholesTest,ShlPlusShrTest2)2282 TEST_F(PeepholesTest, ShlPlusShrTest2)
2283 {
2284 // not applied, same inputs but not a constant
2285 GRAPH(GetGraph())
2286 {
2287 PARAMETER(0U, 0U).s32();
2288 PARAMETER(1U, 1U).s32();
2289
2290 BASIC_BLOCK(2U, -1L)
2291 {
2292 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2293 INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
2294 INST(4U, Opcode::Return).s32().Inputs(3U);
2295 }
2296 }
2297 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
2298 auto graph = CreateEmptyGraph();
2299 GRAPH(graph)
2300 {
2301 PARAMETER(0U, 0U).s32();
2302 PARAMETER(1U, 1U).s32();
2303
2304 BASIC_BLOCK(2U, -1L)
2305 {
2306 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2307 INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
2308 INST(4U, Opcode::Return).s32().Inputs(3U);
2309 }
2310 }
2311 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2312 }
2313
2314 // Checking the shift with zero constant
TEST_F(PeepholesTest,ShrZeroTest)2315 TEST_F(PeepholesTest, ShrZeroTest)
2316 {
2317 GRAPH(GetGraph())
2318 {
2319 PARAMETER(0U, 0U).u64();
2320 CONSTANT(1U, 0U);
2321 CONSTANT(2U, 1U);
2322
2323 BASIC_BLOCK(2U, -1L)
2324 {
2325 INST(3U, Opcode::Shr).u64().Inputs(0U, 1U);
2326 INST(4U, Opcode::Shr).u64().Inputs(0U, 2U);
2327
2328 INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
2329 INST(6U, Opcode::Return).u64().Inputs(5U);
2330 }
2331 }
2332 GetGraph()->RunPass<Peepholes>();
2333
2334 ASSERT_TRUE(INS(3U).GetUsers().Empty());
2335
2336 ASSERT_TRUE(CheckInputs(INS(5U), {0U, 4U}));
2337 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
2338 }
2339
2340 // Checking repeated shifts for constants with the same types
TEST_F(PeepholesTest,ShrRepeatConstTest1)2341 TEST_F(PeepholesTest, ShrRepeatConstTest1)
2342 {
2343 GRAPH(GetGraph())
2344 {
2345 PARAMETER(0U, 0U).u64();
2346 CONSTANT(1U, 5U);
2347 CONSTANT(2U, 6U);
2348
2349 BASIC_BLOCK(2U, -1L)
2350 {
2351 INST(3U, Opcode::Shr).u64().Inputs(0U, 1U);
2352 INST(4U, Opcode::Shr).u64().Inputs(3U, 2U);
2353 INST(5U, Opcode::Return).u64().Inputs(4U);
2354 }
2355 }
2356 GetGraph()->RunPass<Peepholes>();
2357
2358 ASSERT_NE(INS(2U).GetNext(), nullptr);
2359 auto const3 = static_cast<ConstantInst *>(INS(2U).GetNext());
2360 ASSERT_TRUE(const3->IsEqualConst(11U));
2361
2362 ASSERT_TRUE(INS(3U).GetUsers().Empty());
2363 ASSERT_EQ(INS(3U).GetOpcode(), Opcode::Shr);
2364 ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2365 ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Shr);
2366 ASSERT_EQ(INS(4U).GetInput(0U).GetInst(), &INS(0U));
2367 ASSERT_EQ(INS(4U).GetInput(1U).GetInst(), const3);
2368
2369 ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2370 }
2371
2372 // Checking repeated shifts for constants with different types
TEST_F(PeepholesTest,ShrRepeatConstTest2)2373 TEST_F(PeepholesTest, ShrRepeatConstTest2)
2374 {
2375 GRAPH(GetGraph())
2376 {
2377 PARAMETER(0U, 0U).u32();
2378 CONSTANT(1U, 5U);
2379 CONSTANT(2U, 6U);
2380
2381 BASIC_BLOCK(2U, -1L)
2382 {
2383 INST(3U, Opcode::Shr).u16().Inputs(0U, 1U);
2384 INST(4U, Opcode::Shr).u32().Inputs(3U, 2U);
2385 INST(5U, Opcode::Return).u32().Inputs(4U);
2386 }
2387 }
2388 GetGraph()->RunPass<Peepholes>();
2389
2390 ASSERT_EQ(INS(2U).GetNext(), nullptr);
2391
2392 ASSERT_TRUE(CheckInputs(INS(3U), {0U, 1U}));
2393 ASSERT_TRUE(CheckUsers(INS(3U), {4U}));
2394 ASSERT_EQ(INS(3U).GetOpcode(), Opcode::Shr);
2395 ASSERT_TRUE(CheckInputs(INS(4U), {3U, 2U}));
2396 ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2397 ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Shr);
2398
2399 ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2400 }
2401
2402 // Checking the shift for a constant greater than the type size
SRC_GRAPH(ShrBigConstTest,Graph * graph)2403 SRC_GRAPH(ShrBigConstTest, Graph *graph)
2404 {
2405 GRAPH(graph)
2406 {
2407 PARAMETER(0U, 0U).u64();
2408 PARAMETER(1U, 1U).u32();
2409 PARAMETER(2U, 2U).u16();
2410 PARAMETER(3U, 3U).u8();
2411 CONSTANT(4U, 127U);
2412
2413 BASIC_BLOCK(2U, -1L)
2414 {
2415 INST(5U, Opcode::Shr).u64().Inputs(0U, 4U);
2416 INST(6U, Opcode::Shr).u32().Inputs(1U, 4U);
2417 INST(7U, Opcode::Shr).u16().Inputs(2U, 4U);
2418 INST(8U, Opcode::Shr).u8().Inputs(3U, 4U);
2419 INST(20U, Opcode::SaveState).NoVregs();
2420 INST(9U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 7U, 8U, 20U);
2421 INST(10U, Opcode::Return).u64().Inputs(9U);
2422 }
2423 }
2424 }
2425
TEST_F(PeepholesTest,ShrBigConstTest)2426 TEST_F(PeepholesTest, ShrBigConstTest)
2427 {
2428 src_graph::ShrBigConstTest::CREATE(GetGraph());
2429 GetGraph()->RunPass<Peepholes>();
2430
2431 ASSERT_NE(INS(4U).GetNext(), nullptr);
2432 auto const64 = static_cast<ConstantInst *>(INS(4U).GetNext());
2433 ASSERT_TRUE(const64->IsEqualConst(63U));
2434
2435 ASSERT_NE(const64->GetNext(), nullptr);
2436 auto const32 = static_cast<ConstantInst *>(const64->GetNext());
2437 ASSERT_TRUE(const32->IsEqualConst(31U));
2438
2439 ASSERT_NE(const32->GetNext(), nullptr);
2440 auto const16 = static_cast<ConstantInst *>(const32->GetNext());
2441 ASSERT_TRUE(const16->IsEqualConst(15U));
2442
2443 ASSERT_NE(const16->GetNext(), nullptr);
2444 auto const8 = static_cast<ConstantInst *>(const16->GetNext());
2445 ASSERT_TRUE(const8->IsEqualConst(7U));
2446
2447 ASSERT_EQ(INS(5U).GetInput(0U).GetInst(), &INS(0U));
2448 ASSERT_EQ(INS(5U).GetInput(1U).GetInst(), const64);
2449 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Shr);
2450
2451 ASSERT_EQ(INS(6U).GetInput(0U).GetInst(), &INS(1U));
2452 ASSERT_EQ(INS(6U).GetInput(1U).GetInst(), const32);
2453 ASSERT_EQ(INS(6U).GetOpcode(), Opcode::Shr);
2454
2455 ASSERT_EQ(INS(7U).GetInput(0U).GetInst(), &INS(2U));
2456 ASSERT_EQ(INS(7U).GetInput(1U).GetInst(), const16);
2457 ASSERT_EQ(INS(7U).GetOpcode(), Opcode::Shr);
2458
2459 ASSERT_EQ(INS(8U).GetInput(0U).GetInst(), &INS(3U));
2460 ASSERT_EQ(INS(8U).GetInput(1U).GetInst(), const8);
2461 ASSERT_EQ(INS(8U).GetOpcode(), Opcode::Shr);
2462 }
2463
2464 // Checking the shift with zero constant
TEST_F(PeepholesTest,AShrZeroTest)2465 TEST_F(PeepholesTest, AShrZeroTest)
2466 {
2467 GRAPH(GetGraph())
2468 {
2469 PARAMETER(0U, 0U).u64();
2470 CONSTANT(1U, 0U);
2471 CONSTANT(2U, 1U);
2472
2473 BASIC_BLOCK(2U, -1L)
2474 {
2475 INST(3U, Opcode::AShr).u64().Inputs(0U, 1U);
2476 INST(4U, Opcode::AShr).u64().Inputs(0U, 2U);
2477
2478 INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
2479 INST(6U, Opcode::Return).u64().Inputs(5U);
2480 }
2481 }
2482 GetGraph()->RunPass<Peepholes>();
2483
2484 ASSERT_TRUE(INS(3U).GetUsers().Empty());
2485
2486 ASSERT_TRUE(CheckInputs(INS(5U), {0U, 4U}));
2487 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
2488 }
2489
2490 // Checking repeated shifts for constants with the same types
TEST_F(PeepholesTest,AShrRepeatConstTest1)2491 TEST_F(PeepholesTest, AShrRepeatConstTest1)
2492 {
2493 GRAPH(GetGraph())
2494 {
2495 PARAMETER(0U, 0U).u64();
2496 CONSTANT(1U, 5U);
2497 CONSTANT(2U, 6U);
2498
2499 BASIC_BLOCK(2U, -1L)
2500 {
2501 INST(3U, Opcode::AShr).u64().Inputs(0U, 1U);
2502 INST(4U, Opcode::AShr).u64().Inputs(3U, 2U);
2503 INST(5U, Opcode::Return).u64().Inputs(4U);
2504 }
2505 }
2506 GetGraph()->RunPass<Peepholes>();
2507
2508 ASSERT_NE(INS(2U).GetNext(), nullptr);
2509 auto const3 = static_cast<ConstantInst *>(INS(2U).GetNext());
2510 ASSERT_TRUE(const3->IsEqualConst(11U));
2511
2512 ASSERT_TRUE(INS(3U).GetUsers().Empty());
2513 ASSERT_EQ(INS(3U).GetOpcode(), Opcode::AShr);
2514 ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2515 ASSERT_EQ(INS(4U).GetOpcode(), Opcode::AShr);
2516 ASSERT_EQ(INS(4U).GetInput(0U).GetInst(), &INS(0U));
2517 ASSERT_EQ(INS(4U).GetInput(1U).GetInst(), const3);
2518
2519 ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2520 }
2521
2522 // Checking repeated shifts for constants with different types
TEST_F(PeepholesTest,AShrRepeatConstTest2)2523 TEST_F(PeepholesTest, AShrRepeatConstTest2)
2524 {
2525 GRAPH(GetGraph())
2526 {
2527 PARAMETER(0U, 0U).u32();
2528 CONSTANT(1U, 5U);
2529 CONSTANT(2U, 6U);
2530
2531 BASIC_BLOCK(2U, -1L)
2532 {
2533 INST(3U, Opcode::AShr).u16().Inputs(0U, 1U);
2534 INST(4U, Opcode::AShr).u32().Inputs(3U, 2U);
2535 INST(5U, Opcode::Return).u32().Inputs(4U);
2536 }
2537 }
2538 GetGraph()->RunPass<Peepholes>();
2539
2540 ASSERT_EQ(INS(2U).GetNext(), nullptr);
2541
2542 ASSERT_TRUE(CheckInputs(INS(3U), {0U, 1U}));
2543 ASSERT_TRUE(CheckUsers(INS(3U), {4U}));
2544 ASSERT_EQ(INS(3U).GetOpcode(), Opcode::AShr);
2545 ASSERT_TRUE(CheckInputs(INS(4U), {3U, 2U}));
2546 ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2547 ASSERT_EQ(INS(4U).GetOpcode(), Opcode::AShr);
2548
2549 ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2550 }
2551
2552 // Checking the shift for a constant greater than the type size
SRC_GRAPH(AShrBigConstTest,Graph * graph)2553 SRC_GRAPH(AShrBigConstTest, Graph *graph)
2554 {
2555 GRAPH(graph)
2556 {
2557 PARAMETER(0U, 0U).u64();
2558 PARAMETER(1U, 1U).u32();
2559 PARAMETER(2U, 2U).u16();
2560 PARAMETER(3U, 3U).u8();
2561 CONSTANT(4U, 127U);
2562
2563 BASIC_BLOCK(2U, -1L)
2564 {
2565 INST(5U, Opcode::AShr).u64().Inputs(0U, 4U);
2566 INST(6U, Opcode::AShr).u32().Inputs(1U, 4U);
2567 INST(7U, Opcode::AShr).u16().Inputs(2U, 4U);
2568 INST(8U, Opcode::AShr).u8().Inputs(3U, 4U);
2569 INST(20U, Opcode::SaveState).NoVregs();
2570 INST(10U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 7U, 8U, 20U);
2571 INST(9U, Opcode::Return).u64().Inputs(10U);
2572 }
2573 }
2574 }
2575
TEST_F(PeepholesTest,AShrBigConstTest)2576 TEST_F(PeepholesTest, AShrBigConstTest)
2577 {
2578 src_graph::AShrBigConstTest::CREATE(GetGraph());
2579 GetGraph()->RunPass<Peepholes>();
2580
2581 ASSERT_NE(INS(4U).GetNext(), nullptr);
2582 auto const64 = static_cast<ConstantInst *>(INS(4U).GetNext());
2583 ASSERT_TRUE(const64->IsEqualConst(63U));
2584
2585 ASSERT_NE(const64->GetNext(), nullptr);
2586 auto const32 = static_cast<ConstantInst *>(const64->GetNext());
2587 ASSERT_TRUE(const32->IsEqualConst(31U));
2588
2589 ASSERT_NE(const32->GetNext(), nullptr);
2590 auto const16 = static_cast<ConstantInst *>(const32->GetNext());
2591 ASSERT_TRUE(const16->IsEqualConst(15U));
2592
2593 ASSERT_NE(const16->GetNext(), nullptr);
2594 auto const8 = static_cast<ConstantInst *>(const16->GetNext());
2595 ASSERT_TRUE(const8->IsEqualConst(7U));
2596
2597 ASSERT_EQ(INS(5U).GetInput(0U).GetInst(), &INS(0U));
2598 ASSERT_EQ(INS(5U).GetInput(1U).GetInst(), const64);
2599 ASSERT_EQ(INS(5U).GetOpcode(), Opcode::AShr);
2600
2601 ASSERT_EQ(INS(6U).GetInput(0U).GetInst(), &INS(1U));
2602 ASSERT_EQ(INS(6U).GetInput(1U).GetInst(), const32);
2603 ASSERT_EQ(INS(6U).GetOpcode(), Opcode::AShr);
2604
2605 ASSERT_EQ(INS(7U).GetInput(0U).GetInst(), &INS(2U));
2606 ASSERT_EQ(INS(7U).GetInput(1U).GetInst(), const16);
2607 ASSERT_EQ(INS(7U).GetOpcode(), Opcode::AShr);
2608
2609 ASSERT_EQ(INS(8U).GetInput(0U).GetInst(), &INS(3U));
2610 ASSERT_EQ(INS(8U).GetInput(1U).GetInst(), const8);
2611 ASSERT_EQ(INS(8U).GetOpcode(), Opcode::AShr);
2612 }
2613
TEST_F(PeepholesTest,ShlPlusAShrTest1)2614 TEST_F(PeepholesTest, ShlPlusAShrTest1)
2615 {
2616 GRAPH(GetGraph())
2617 {
2618 PARAMETER(0U, 0U).s32();
2619 CONSTANT(1U, 0x18U);
2620
2621 BASIC_BLOCK(2U, -1L)
2622 {
2623 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2624 INST(3U, Opcode::AShr).s32().Inputs(2U, 1U);
2625 INST(4U, Opcode::Return).s32().Inputs(3U);
2626 }
2627 }
2628 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2629 GetGraph()->RunPass<Cleanup>();
2630 auto graph = CreateEmptyGraph();
2631 GRAPH(graph)
2632 {
2633 PARAMETER(0U, 0U).s32();
2634
2635 BASIC_BLOCK(2U, -1L)
2636 {
2637 INST(6U, Opcode::Cast).s8().SrcType(DataType::INT32).Inputs(0U);
2638 INST(4U, Opcode::Return).s32().Inputs(6U);
2639 }
2640 }
2641 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2642 }
2643
TEST_F(PeepholesTest,ShlPlusAShrTest2)2644 TEST_F(PeepholesTest, ShlPlusAShrTest2)
2645 {
2646 GRAPH(GetGraph())
2647 {
2648 PARAMETER(0U, 0U).s32();
2649 CONSTANT(1U, 0x10U);
2650
2651 BASIC_BLOCK(2U, -1L)
2652 {
2653 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2654 INST(3U, Opcode::AShr).s32().Inputs(2U, 1U);
2655 INST(4U, Opcode::Return).s32().Inputs(3U);
2656 }
2657 }
2658 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2659 GetGraph()->RunPass<Cleanup>();
2660 auto graph = CreateEmptyGraph();
2661 GRAPH(graph)
2662 {
2663 PARAMETER(0U, 0U).s32();
2664
2665 BASIC_BLOCK(2U, -1L)
2666 {
2667 INST(6U, Opcode::Cast).s16().SrcType(DataType::INT32).Inputs(0U);
2668 INST(4U, Opcode::Return).s32().Inputs(6U);
2669 }
2670 }
2671 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2672 }
2673
TEST_F(PeepholesTest,ShlPlusAShrTest3)2674 TEST_F(PeepholesTest, ShlPlusAShrTest3)
2675 {
2676 GRAPH(GetGraph())
2677 {
2678 PARAMETER(0U, 0U).s64();
2679 CONSTANT(1U, 0x8U);
2680
2681 BASIC_BLOCK(2U, -1L)
2682 {
2683 INST(2U, Opcode::Shl).s64().Inputs(0U, 1U);
2684 INST(3U, Opcode::AShr).s64().Inputs(2U, 1U);
2685 INST(4U, Opcode::Return).s32().Inputs(3U);
2686 }
2687 }
2688 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2689 GetGraph()->RunPass<Cleanup>();
2690 auto graph = CreateEmptyGraph();
2691 GRAPH(graph)
2692 {
2693 PARAMETER(0U, 0U).s64();
2694
2695 BASIC_BLOCK(2U, -1L)
2696 {
2697 INST(6U, Opcode::Cast).s32().SrcType(DataType::INT64).Inputs(0U);
2698 INST(4U, Opcode::Return).s32().Inputs(6U);
2699 }
2700 }
2701 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2702 }
2703
TEST_F(PeepholesTest,ShlPlusAShrTest4)2704 TEST_F(PeepholesTest, ShlPlusAShrTest4)
2705 {
2706 // not applied, different constants
2707 GRAPH(GetGraph())
2708 {
2709 PARAMETER(0U, 0U).s32();
2710 CONSTANT(1U, 0x18U);
2711 CONSTANT(5U, 0x10U);
2712
2713 BASIC_BLOCK(2U, -1L)
2714 {
2715 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2716 INST(3U, Opcode::AShr).s32().Inputs(2U, 5U);
2717 INST(4U, Opcode::Return).s32().Inputs(3U);
2718 }
2719 }
2720 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
2721 auto graph = CreateEmptyGraph();
2722 GRAPH(graph)
2723 {
2724 PARAMETER(0U, 0U).s32();
2725 CONSTANT(1U, 0x18U);
2726 CONSTANT(5U, 0x10U);
2727
2728 BASIC_BLOCK(2U, -1L)
2729 {
2730 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2731 INST(3U, Opcode::AShr).s32().Inputs(2U, 5U);
2732 INST(4U, Opcode::Return).s32().Inputs(3U);
2733 }
2734 }
2735 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2736 }
2737
TEST_F(PeepholesTest,ShlPlusAShrTest5)2738 TEST_F(PeepholesTest, ShlPlusAShrTest5)
2739 {
2740 // not applied, same inputs but not a constant
2741 GRAPH(GetGraph())
2742 {
2743 PARAMETER(0U, 0U).s32();
2744 PARAMETER(1U, 1U).s32();
2745
2746 BASIC_BLOCK(2U, -1L)
2747 {
2748 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2749 INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
2750 INST(4U, Opcode::Return).s32().Inputs(3U);
2751 }
2752 }
2753 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
2754 auto graph = CreateEmptyGraph();
2755 GRAPH(graph)
2756 {
2757 PARAMETER(0U, 0U).s32();
2758 PARAMETER(1U, 1U).s32();
2759
2760 BASIC_BLOCK(2U, -1L)
2761 {
2762 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2763 INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
2764 INST(4U, Opcode::Return).s32().Inputs(3U);
2765 }
2766 }
2767 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2768 }
2769
TEST_F(PeepholesTest,TestMulCase1)2770 TEST_F(PeepholesTest, TestMulCase1)
2771 {
2772 // case 1:
2773 // 0. Const 1
2774 // 1. MUL v5, v0 -> {v2, ...}
2775 // 2. INS v1
2776 // ===>
2777 // 0. Const 1
2778 // 1. MUL v5, v0
2779 // 2. INS v5
2780 GRAPH(GetGraph())
2781 {
2782 PARAMETER(0U, 0U).u64();
2783 CONSTANT(3U, 1U);
2784 BASIC_BLOCK(2U, -1L)
2785 {
2786 INST(6U, Opcode::Mul).u64().Inputs(0U, 3U);
2787 INST(12U, Opcode::Mul).u16().Inputs(0U, 3U);
2788 INST(20U, Opcode::SaveState).NoVregs();
2789 INST(21U, Opcode::CallStatic).u64().InputsAutoType(6U, 12U, 20U);
2790 INST(14U, Opcode::Return).u64().Inputs(21U);
2791 }
2792 }
2793 GetGraph()->RunPass<Peepholes>();
2794
2795 ASSERT_EQ(INS(21U).GetInput(0U).GetInst(), &INS(0U));
2796 ASSERT_TRUE(INS(6U).GetUsers().Empty());
2797
2798 ASSERT_EQ(INS(21U).GetInput(1U).GetInst(), &INS(0U));
2799 ASSERT_TRUE(INS(12U).GetUsers().Empty());
2800 }
2801
TEST_F(PeepholesTest,TestMulCase2)2802 TEST_F(PeepholesTest, TestMulCase2)
2803 {
2804 // case 2:
2805 // 0. Const -1
2806 // 1. MUL v5, v0
2807 // 2. INS v1
2808 // ===>
2809 // 0. Const -1
2810 // 1. MUL v5, v0
2811 // 3. NEG v5 -> {v2, ...}
2812 // 2. INS v3
2813 GRAPH(GetGraph())
2814 {
2815 PARAMETER(0U, 0U).u64();
2816 CONSTANT(3U, -1L);
2817 BASIC_BLOCK(2U, -1L)
2818 {
2819 INST(6U, Opcode::Mul).u64().Inputs(0U, 3U);
2820 INST(20U, Opcode::SaveState).NoVregs();
2821 INST(13U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
2822 INST(12U, Opcode::Return).u64().Inputs(13U);
2823 }
2824 }
2825 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2826 GetGraph()->RunPass<Cleanup>();
2827 auto graph = CreateEmptyGraph();
2828 GRAPH(graph)
2829 {
2830 PARAMETER(0U, 0U).u64();
2831 BASIC_BLOCK(2U, -1L)
2832 {
2833 INST(6U, Opcode::Neg).u64().Inputs(0U);
2834 INST(20U, Opcode::SaveState).NoVregs();
2835 INST(13U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
2836 INST(12U, Opcode::Return).u64().Inputs(13U);
2837 }
2838 }
2839 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2840 }
2841
TEST_F(PeepholesTest,TestMulCase3)2842 TEST_F(PeepholesTest, TestMulCase3)
2843 {
2844 // case 3:
2845 // 0. Const 2
2846 // 1. MUL v5, v0
2847 // 2. INS v1
2848 // ===>
2849 // 0. Const -1
2850 // 1. MUL v5, v0
2851 // 3. ADD v5 , V5 -> {v2, ...}
2852 // 2. INS v3
2853 GRAPH(GetGraph())
2854 {
2855 PARAMETER(0U, 0U).u64();
2856 CONSTANT(3U, 2U);
2857 BASIC_BLOCK(2U, -1L)
2858 {
2859 INST(6U, Opcode::Mul).u64().Inputs(0U, 3U);
2860 INST(20U, Opcode::SaveState).NoVregs();
2861 INST(13U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
2862 INST(12U, Opcode::Return).u64().Inputs(13U);
2863 }
2864 }
2865 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2866 GetGraph()->RunPass<Cleanup>();
2867 auto graph = CreateEmptyGraph();
2868 GRAPH(graph)
2869 {
2870 PARAMETER(0U, 0U).u64();
2871 BASIC_BLOCK(2U, -1L)
2872 {
2873 INST(6U, Opcode::Add).u64().Inputs(0U, 0U);
2874 INST(20U, Opcode::SaveState).NoVregs();
2875 INST(13U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
2876 INST(12U, Opcode::Return).u64().Inputs(13U);
2877 }
2878 }
2879 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2880 }
2881
SRC_GRAPH(TestMulCase4,Graph * graph)2882 SRC_GRAPH(TestMulCase4, Graph *graph)
2883 {
2884 GRAPH(graph)
2885 {
2886 PARAMETER(0U, 0U).u64();
2887 PARAMETER(1U, 1U).s64();
2888 PARAMETER(2U, 2U).u16();
2889 PARAMETER(13U, 3U).f32();
2890 PARAMETER(14U, 4U).f64();
2891 CONSTANT(3U, 4U);
2892 CONSTANT(4U, 16U);
2893 CONSTANT(5U, 512U);
2894 CONSTANT(15U, 4.0F);
2895 CONSTANT(16U, 16.0_D);
2896 BASIC_BLOCK(2U, -1L)
2897 {
2898 INST(6U, Opcode::Mul).u64().Inputs(0U, 3U);
2899 INST(8U, Opcode::Mul).s64().Inputs(1U, 4U);
2900 INST(10U, Opcode::Mul).u16().Inputs(2U, 5U);
2901 INST(17U, Opcode::Mul).f32().Inputs(13U, 15U);
2902 INST(19U, Opcode::Mul).f64().Inputs(14U, 16U);
2903 INST(20U, Opcode::SaveState).NoVregs();
2904 INST(21U, Opcode::CallStatic).u64().InputsAutoType(6U, 8U, 10U, 17U, 19U, 20U);
2905 INST(22U, Opcode::Return).u64().Inputs(21U);
2906 }
2907 }
2908 }
2909
OUT_GRAPH(TestMulCase4,Graph * graph)2910 OUT_GRAPH(TestMulCase4, Graph *graph)
2911 {
2912 GRAPH(graph)
2913 {
2914 PARAMETER(0U, 0U).u64();
2915 PARAMETER(1U, 1U).s64();
2916 PARAMETER(2U, 2U).u16();
2917 PARAMETER(13U, 3U).f32();
2918 PARAMETER(14U, 4U).f64();
2919 CONSTANT(3U, 4U);
2920 CONSTANT(15U, 4.0F);
2921 CONSTANT(16U, 16.0_D);
2922 CONSTANT(23U, 2U);
2923 CONSTANT(24U, 9U);
2924 BASIC_BLOCK(2U, -1L)
2925 {
2926 INST(6U, Opcode::Shl).u64().Inputs(0U, 23U);
2927 INST(8U, Opcode::Shl).s64().Inputs(1U, 3U);
2928 INST(10U, Opcode::Shl).u16().Inputs(2U, 24U);
2929 INST(17U, Opcode::Mul).f32().Inputs(13U, 15U);
2930 INST(19U, Opcode::Mul).f64().Inputs(14U, 16U);
2931 INST(20U, Opcode::SaveState).NoVregs();
2932 INST(21U, Opcode::CallStatic).u64().InputsAutoType(6U, 8U, 10U, 17U, 19U, 20U);
2933 INST(22U, Opcode::Return).u64().Inputs(21U);
2934 }
2935 }
2936 }
2937
TEST_F(PeepholesTest,TestMulCase4)2938 TEST_F(PeepholesTest, TestMulCase4)
2939 {
2940 // case 4:
2941 // 0. Const 2^N
2942 // 1. MUL v5, v0
2943 // 2. INS v1
2944 // ===>
2945 // 0. Const -1
2946 // 1. MUL v5, v0
2947 // 3. SHL v5 , N -> {v2, ...}
2948 // 2. INS v3
2949 src_graph::TestMulCase4::CREATE(GetGraph());
2950 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2951 GetGraph()->RunPass<Cleanup>();
2952 auto graph = CreateEmptyGraph();
2953 out_graph::TestMulCase4::CREATE(graph);
2954 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2955 }
2956
TEST_F(PeepholesTest,TestDivCase1)2957 TEST_F(PeepholesTest, TestDivCase1)
2958 {
2959 // case 1:
2960 // 0. Const 1
2961 // 1. DIV v5, v0 -> {v2, ...}
2962 // 2. INS v1
2963 // ===>
2964 // 0. Const 1
2965 // 1. DIV v5, v0
2966 // 3. MOV v5 -> {v2, ...}
2967 // 2. INS v3
2968 GRAPH(GetGraph())
2969 {
2970 PARAMETER(0U, 0U).u64();
2971 CONSTANT(3U, 1U);
2972 BASIC_BLOCK(2U, -1L)
2973 {
2974 INST(6U, Opcode::Div).u64().Inputs(0U, 3U);
2975 INST(12U, Opcode::Div).u16().Inputs(0U, 3U);
2976 INST(20U, Opcode::SaveState).NoVregs();
2977 INST(21U, Opcode::CallStatic).u64().InputsAutoType(6U, 12U, 20U);
2978 INST(22U, Opcode::Return).u64().Inputs(21U);
2979 }
2980 }
2981 GetGraph()->RunPass<Peepholes>();
2982 GraphChecker(GetGraph()).Check();
2983
2984 ASSERT_EQ(INS(21U).GetInput(0U).GetInst(), &INS(0U));
2985 ASSERT_TRUE(INS(6U).GetUsers().Empty());
2986
2987 ASSERT_EQ(INS(21U).GetInput(1U).GetInst(), &INS(0U));
2988 ASSERT_TRUE(INS(12U).GetUsers().Empty());
2989 }
2990
TEST_F(PeepholesTest,TestDivCase2)2991 TEST_F(PeepholesTest, TestDivCase2)
2992 {
2993 // case 2:
2994 // 0. Const -1
2995 // 1. DIV v5, v0 -> {v2, ...}
2996 // 2. INS v1
2997 // ===>
2998 // 0. Const -1
2999 // 1. DIV v5, v0
3000 // 3. NEG v5 -> {v2, ...}
3001 // 2. INS v3
3002 GRAPH(GetGraph())
3003 {
3004 PARAMETER(0U, 0U).u64();
3005 CONSTANT(3U, -1L);
3006 BASIC_BLOCK(2U, -1L)
3007 {
3008 INST(6U, Opcode::Div).u64().Inputs(0U, 3U);
3009 INST(20U, Opcode::SaveState).NoVregs();
3010 INST(21U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
3011 INST(22U, Opcode::Return).u64().Inputs(21U);
3012 }
3013 }
3014 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
3015 GetGraph()->RunPass<Cleanup>();
3016 auto graph = CreateEmptyGraph();
3017 GRAPH(graph)
3018 {
3019 PARAMETER(0U, 0U).u64();
3020 BASIC_BLOCK(2U, -1L)
3021 {
3022 INST(6U, Opcode::Neg).u64().Inputs(0U);
3023 INST(20U, Opcode::SaveState).NoVregs();
3024 INST(13U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
3025 INST(12U, Opcode::Return).u64().Inputs(13U);
3026 }
3027 }
3028 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3029 }
3030
TEST_F(PeepholesTest,TestDivCase3Unsigned)3031 TEST_F(PeepholesTest, TestDivCase3Unsigned)
3032 {
3033 for (auto type : {DataType::UINT8, DataType::UINT16, DataType::UINT32, DataType::UINT64}) {
3034 auto graph1 = CreateEmptyGraph();
3035 GRAPH(graph1)
3036 {
3037 PARAMETER(0U, 0U);
3038 INS(0U).SetType(type);
3039 CONSTANT(1U, 4U);
3040 BASIC_BLOCK(2U, -1L)
3041 {
3042 INST(2U, Opcode::Div).Inputs(0U, 1U);
3043 INS(2U).SetType(type);
3044 INST(3U, Opcode::Return).Inputs(2U);
3045 INS(3U).SetType(type);
3046 }
3047 }
3048 ASSERT_TRUE(graph1->RunPass<Peepholes>());
3049 graph1->RunPass<Cleanup>();
3050 auto graph2 = CreateEmptyGraph();
3051 GRAPH(graph2)
3052 {
3053 PARAMETER(0U, 0U);
3054 INS(0U).SetType(type);
3055 CONSTANT(1U, 2U);
3056 BASIC_BLOCK(2U, -1L)
3057 {
3058 INST(2U, Opcode::Shr).Inputs(0U, 1U);
3059 INS(2U).SetType(type);
3060 INST(3U, Opcode::Return).Inputs(2U);
3061 INS(3U).SetType(type);
3062 }
3063 }
3064 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
3065 }
3066 }
3067
TEST_F(PeepholesTest,TestDivCase3SignedPositive)3068 TEST_F(PeepholesTest, TestDivCase3SignedPositive)
3069 {
3070 for (auto type : {DataType::INT8, DataType::INT16, DataType::INT32, DataType::INT64}) {
3071 auto graph1 = CreateEmptyGraph();
3072 GRAPH(graph1)
3073 {
3074 PARAMETER(0U, 0U);
3075 INS(0U).SetType(type);
3076 CONSTANT(1U, 4U);
3077 BASIC_BLOCK(2U, -1L)
3078 {
3079 INST(2U, Opcode::Div).Inputs(0U, 1U);
3080 INS(2U).SetType(type);
3081 INST(3U, Opcode::Return).Inputs(2U);
3082 INS(3U).SetType(type);
3083 }
3084 }
3085
3086 ASSERT_FALSE(graph1->RunPass<Peepholes>());
3087 graph1->RunPass<Cleanup>();
3088
3089 auto graph2 = CreateEmptyGraph();
3090 GRAPH(graph2)
3091 {
3092 PARAMETER(0U, 0U);
3093 INS(0U).SetType(type);
3094 CONSTANT(1U, 4U);
3095 BASIC_BLOCK(2U, -1L)
3096 {
3097 INST(2U, Opcode::Div).Inputs(0U, 1U);
3098 INS(2U).SetType(type);
3099 INST(3U, Opcode::Return).Inputs(2U);
3100 INS(3U).SetType(type);
3101 }
3102 }
3103 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
3104 }
3105 }
3106
TEST_F(PeepholesTest,TestDivCase3SignedNegative)3107 TEST_F(PeepholesTest, TestDivCase3SignedNegative)
3108 {
3109 for (auto type : {DataType::INT8, DataType::INT16, DataType::INT32, DataType::INT64}) {
3110 auto graph1 = CreateEmptyGraph();
3111 GRAPH(graph1)
3112 {
3113 PARAMETER(0U, 0U);
3114 INS(0U).SetType(type);
3115 CONSTANT(1U, -16L);
3116 BASIC_BLOCK(2U, -1L)
3117 {
3118 INST(2U, Opcode::Div).Inputs(0U, 1U);
3119 INS(2U).SetType(type);
3120 INST(3U, Opcode::Return).Inputs(2U);
3121 INS(3U).SetType(type);
3122 }
3123 }
3124
3125 ASSERT_FALSE(graph1->RunPass<Peepholes>());
3126 graph1->RunPass<Cleanup>();
3127
3128 auto graph2 = CreateEmptyGraph();
3129 GRAPH(graph2)
3130 {
3131 PARAMETER(0U, 0U);
3132 INS(0U).SetType(type);
3133 CONSTANT(1U, -16L);
3134 BASIC_BLOCK(2U, -1L)
3135 {
3136 INST(2U, Opcode::Div).Inputs(0U, 1U);
3137 INS(2U).SetType(type);
3138 INST(3U, Opcode::Return).Inputs(2U);
3139 INS(3U).SetType(type);
3140 }
3141 }
3142 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
3143 }
3144 }
3145
TEST_F(PeepholesTest,TestLenArray1)3146 TEST_F(PeepholesTest, TestLenArray1)
3147 {
3148 // 1. .... ->{v2}
3149 // 2. NewArray v1 ->{v3,..}
3150 // 3. LenArray v2 ->{v4, v5...}
3151 // ===>
3152 // 1. .... ->{v2, v4, v5, ...}
3153 // 2. NewArray v1 ->{v3,..}
3154 // 3. LenArray v2
3155 GRAPH(GetGraph())
3156 {
3157 CONSTANT(0U, 10U);
3158 BASIC_BLOCK(2U, 1U)
3159 {
3160 INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
3161 INST(1U, Opcode::NewArray).ref().Inputs(44U, 0U);
3162 INST(2U, Opcode::LenArray).s32().Inputs(1U);
3163 INST(3U, Opcode::Return).s32().Inputs(2U);
3164 }
3165 }
3166 GetGraph()->RunPass<Peepholes>();
3167 GraphChecker(GetGraph()).Check();
3168 auto cnst = INS(3U).GetInput(0U).GetInst();
3169 ASSERT_EQ(cnst->GetOpcode(), Opcode::Constant);
3170 ASSERT_TRUE(INS(2U).GetUsers().Empty());
3171 }
3172
TEST_F(PeepholesTest,TestLenArray2)3173 TEST_F(PeepholesTest, TestLenArray2)
3174 {
3175 // 1. .... ->{v2}
3176 // 2. NewArray v1 ->{v3,..}
3177 // 3. LenArray v2 ->{v4, v5...}
3178 // ===>
3179 // 1. .... ->{v2, v4, v5, ...}
3180 // 2. NewArray v1 ->{v3,..}
3181 // 3. LenArray v2
3182 GRAPH(GetGraph())
3183 {
3184 CONSTANT(0U, 10U);
3185 BASIC_BLOCK(2U, 1U)
3186 {
3187 INST(10U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3188 INST(1U, Opcode::NegativeCheck).s32().Inputs(0U, 10U);
3189 INST(44U, Opcode::LoadAndInitClass).ref().Inputs(10U).TypeId(68U);
3190 INST(2U, Opcode::NewArray).ref().Inputs(44U, 1U);
3191 INST(3U, Opcode::NullCheck).ref().Inputs(2U, 10U);
3192 INST(4U, Opcode::LenArray).s32().Inputs(3U);
3193 INST(5U, Opcode::Return).s32().Inputs(4U);
3194 }
3195 }
3196 GetGraph()->RunPass<Peepholes>();
3197 GraphChecker(GetGraph()).Check();
3198 auto cnst = INS(5U).GetInput(0U).GetInst();
3199 ASSERT_EQ(cnst->GetOpcode(), Opcode::Constant);
3200 ASSERT_TRUE(INS(4U).GetUsers().Empty());
3201 }
3202
SRC_GRAPH(TestPhi1,Graph * graph)3203 SRC_GRAPH(TestPhi1, Graph *graph)
3204 {
3205 GRAPH(graph)
3206 {
3207 PARAMETER(0U, 0U).s32();
3208 PARAMETER(1U, 1U).s32();
3209 BASIC_BLOCK(2U, 3U, 4U)
3210 {
3211 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3212 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3213 }
3214 BASIC_BLOCK(3U, 5U)
3215 {
3216 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3217 }
3218 BASIC_BLOCK(4U, 5U)
3219 {
3220 INST(7U, Opcode::Sub).s32().Inputs(1U, 0U);
3221 }
3222 BASIC_BLOCK(5U, 1U)
3223 {
3224 INST(9U, Opcode::Phi).s32().Inputs(5U, 7U);
3225 INST(10U, Opcode::Phi).s32().Inputs(5U, 7U);
3226 INST(11U, Opcode::Add).s32().Inputs(9U, 0U);
3227 INST(12U, Opcode::Add).s32().Inputs(10U, 1U);
3228 INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3229 INST(14U, Opcode::Return).s32().Inputs(13U);
3230 }
3231 }
3232 }
3233
OUT_GRAPH(TestPhi1,Graph * graph)3234 OUT_GRAPH(TestPhi1, Graph *graph)
3235 {
3236 GRAPH(graph)
3237 {
3238 PARAMETER(0U, 0U).s32();
3239 PARAMETER(1U, 1U).s32();
3240 BASIC_BLOCK(2U, 3U, 4U)
3241 {
3242 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3243 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3244 }
3245 BASIC_BLOCK(3U, 5U)
3246 {
3247 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3248 }
3249 BASIC_BLOCK(4U, 5U)
3250 {
3251 INST(7U, Opcode::Sub).s32().Inputs(1U, 0U);
3252 }
3253 BASIC_BLOCK(5U, 1U)
3254 {
3255 INST(9U, Opcode::Phi).s32().Inputs(5U, 7U);
3256 INST(10U, Opcode::Phi).s32().Inputs(5U, 7U);
3257 INST(11U, Opcode::Add).s32().Inputs(9U, 0U);
3258 INST(12U, Opcode::Add).s32().Inputs(9U, 1U);
3259 INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3260 INST(14U, Opcode::Return).s32().Inputs(13U);
3261 }
3262 }
3263 }
3264
TEST_F(PeepholesTest,TestPhi1)3265 TEST_F(PeepholesTest, TestPhi1)
3266 {
3267 // Users isn't intersect
3268 // 2.type Phi v0, v1 -> v4
3269 // 3.type Phi v0, v1 -> v5
3270 // ===>
3271 // 2.type Phi v0, v1 -> v4, v5
3272 // 3.type Phi v0, v1
3273 src_graph::TestPhi1::CREATE(GetGraph());
3274 GetGraph()->RunPass<Peepholes>();
3275 auto graph = CreateEmptyGraph();
3276 out_graph::TestPhi1::CREATE(graph);
3277 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3278 }
3279
SRC_GRAPH(PhiTestWithChecks,Graph * graph)3280 SRC_GRAPH(PhiTestWithChecks, Graph *graph)
3281 {
3282 GRAPH(graph)
3283 {
3284 PARAMETER(0U, 0U).ref();
3285 PARAMETER(1U, 1U).ref();
3286 BASIC_BLOCK(2U, 3U, 4U)
3287 {
3288 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3289 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3290 }
3291 BASIC_BLOCK(3U, 5U)
3292 {
3293 INST(5U, Opcode::NullCheck).ref().Inputs(0U);
3294 }
3295 BASIC_BLOCK(4U, 5U)
3296 {
3297 INST(7U, Opcode::NullCheck).ref().Inputs(1U);
3298 }
3299 BASIC_BLOCK(5U, 1U)
3300 {
3301 INST(9U, Opcode::Phi).ref().Inputs(5U, 7U);
3302 INST(10U, Opcode::Phi).ref().Inputs(0U, 1U);
3303 INST(12U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3304 INST(11U, Opcode::CallStatic).s32().InputsAutoType(9U, 10U, 12U);
3305 INST(14U, Opcode::Return).s32().Inputs(11U);
3306 }
3307 }
3308 }
3309
OUT_GRAPH(PhiTestWithChecks,Graph * graph)3310 OUT_GRAPH(PhiTestWithChecks, Graph *graph)
3311 {
3312 GRAPH(graph)
3313 {
3314 PARAMETER(0U, 0U).ref();
3315 PARAMETER(1U, 1U).ref();
3316 BASIC_BLOCK(2U, 3U, 4U)
3317 {
3318 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3319 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3320 }
3321 BASIC_BLOCK(3U, 5U)
3322 {
3323 INST(5U, Opcode::NullCheck).ref().Inputs(0U);
3324 }
3325 BASIC_BLOCK(4U, 5U)
3326 {
3327 INST(7U, Opcode::NullCheck).ref().Inputs(1U);
3328 }
3329 BASIC_BLOCK(5U, 1U)
3330 {
3331 INST(9U, Opcode::Phi).ref().Inputs(5U, 7U);
3332 INST(10U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3333 INST(11U, Opcode::CallStatic).s32().InputsAutoType(9U, 9U, 10U);
3334 INST(14U, Opcode::Return).s32().Inputs(11U);
3335 }
3336 }
3337 }
3338
TEST_F(PeepholesTest,PhiTestWithChecks)3339 TEST_F(PeepholesTest, PhiTestWithChecks)
3340 {
3341 // Users isn't intersect
3342 // 2.type Phi v0, v1 -> v4
3343 // 3.type Phi v0, v1 -> v5
3344 // ===>
3345 // 2.type Phi v0, v1 -> v4, v5
3346 // 3.type Phi v0, v1
3347 src_graph::PhiTestWithChecks::CREATE(GetGraph());
3348 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
3349 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
3350 auto graph = CreateEmptyGraph();
3351 out_graph::PhiTestWithChecks::CREATE(graph);
3352 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3353 }
3354
SRC_GRAPH(TestPhi2,Graph * graph)3355 SRC_GRAPH(TestPhi2, Graph *graph)
3356 {
3357 GRAPH(graph)
3358 {
3359 PARAMETER(0U, 0U).s32();
3360 PARAMETER(1U, 1U).s32();
3361 BASIC_BLOCK(2U, 3U, 4U)
3362 {
3363 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3364 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3365 }
3366 BASIC_BLOCK(3U, 5U)
3367 {
3368 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3369 }
3370 BASIC_BLOCK(4U, 5U)
3371 {
3372 INST(7U, Opcode::Sub).s32().Inputs(1U, 0U);
3373 }
3374 BASIC_BLOCK(5U, 1U)
3375 {
3376 INST(9U, Opcode::Phi).s32().Inputs(5U, 7U);
3377 INST(10U, Opcode::Phi).s32().Inputs(5U, 7U);
3378 INST(11U, Opcode::Add).s32().Inputs(9U, 0U);
3379 INST(12U, Opcode::Add).s32().Inputs(9U, 10U);
3380 INST(13U, Opcode::Add).s32().Inputs(10U, 1U);
3381 INST(14U, Opcode::Add).s32().Inputs(11U, 12U);
3382 INST(15U, Opcode::Add).s32().Inputs(13U, 14U);
3383 INST(20U, Opcode::SaveState).NoVregs();
3384 INST(16U, Opcode::CallStatic).v0id().InputsAutoType(9U, 10U, 15U, 20U);
3385 ;
3386 INST(17U, Opcode::Return).s32().Inputs(15U);
3387 }
3388 }
3389 }
3390
OUT_GRAPH(TestPhi2,Graph * graph)3391 OUT_GRAPH(TestPhi2, Graph *graph)
3392 {
3393 GRAPH(graph)
3394 {
3395 PARAMETER(0U, 0U).s32();
3396 PARAMETER(1U, 1U).s32();
3397 BASIC_BLOCK(2U, 3U, 4U)
3398 {
3399 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3400 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3401 }
3402 BASIC_BLOCK(3U, 5U)
3403 {
3404 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3405 }
3406 BASIC_BLOCK(4U, 5U)
3407 {
3408 INST(7U, Opcode::Sub).s32().Inputs(1U, 0U);
3409 }
3410 BASIC_BLOCK(5U, 1U)
3411 {
3412 INST(9U, Opcode::Phi).s32().Inputs(5U, 7U);
3413 INST(10U, Opcode::Phi).s32().Inputs(5U, 7U);
3414 INST(11U, Opcode::Add).s32().Inputs(9U, 0U);
3415 INST(12U, Opcode::Add).s32().Inputs(9U, 9U);
3416 INST(13U, Opcode::Add).s32().Inputs(9U, 1U);
3417 INST(14U, Opcode::Add).s32().Inputs(11U, 12U);
3418 INST(15U, Opcode::Add).s32().Inputs(13U, 14U);
3419 INST(20U, Opcode::SaveState).NoVregs();
3420 INST(16U, Opcode::CallStatic).v0id().InputsAutoType(9U, 9U, 15U, 20U);
3421 INST(17U, Opcode::Return).s32().Inputs(15U);
3422 }
3423 }
3424 }
3425
TEST_F(PeepholesTest,TestPhi2)3426 TEST_F(PeepholesTest, TestPhi2)
3427 {
3428 // Users is intersect
3429 // 2.type Phi v0, v1 -> v4, v5
3430 // 3.type Phi v0, v1 -> v5, v6
3431 // ===>
3432 // 2.type Phi v0, v1 -> v4, v5
3433 // 3.type Phi v0, v1
3434 src_graph::TestPhi2::CREATE(GetGraph());
3435 GetGraph()->RunPass<Peepholes>();
3436 auto graph = CreateEmptyGraph();
3437 out_graph::TestPhi2::CREATE(graph);
3438 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3439 }
3440
SRC_GRAPH(TestPhi3,Graph * graph)3441 SRC_GRAPH(TestPhi3, Graph *graph)
3442 {
3443 GRAPH(graph)
3444 {
3445 PARAMETER(0U, 0U).s32();
3446 PARAMETER(1U, 1U).s32();
3447 BASIC_BLOCK(2U, 3U, 4U)
3448 {
3449 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3450 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3451 }
3452 BASIC_BLOCK(3U, 5U)
3453 {
3454 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U); // Phi 11
3455 INST(6U, Opcode::Add).s32().Inputs(0U, 1U); // Phi 12
3456 }
3457 BASIC_BLOCK(4U, 5U)
3458 {
3459 INST(8U, Opcode::Sub).s32().Inputs(1U, 0U); // Phi 11
3460 INST(9U, Opcode::Add).s32().Inputs(0U, 1U); // Phi 12
3461 }
3462 BASIC_BLOCK(5U, 1U)
3463 {
3464 INST(11U, Opcode::Phi).s32().Inputs(5U, 8U);
3465 INST(12U, Opcode::Phi).s32().Inputs(6U, 9U);
3466 INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3467 INST(20U, Opcode::SaveState).NoVregs();
3468 INST(14U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 20U);
3469 INST(15U, Opcode::Return).s32().Inputs(13U);
3470 }
3471 }
3472 }
3473
OUT_GRAPH(TestPhi3,Graph * graph)3474 OUT_GRAPH(TestPhi3, Graph *graph)
3475 {
3476 GRAPH(graph)
3477 {
3478 PARAMETER(0U, 0U).s32();
3479 PARAMETER(1U, 1U).s32();
3480 BASIC_BLOCK(2U, 3U, 4U)
3481 {
3482 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3483 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3484 }
3485 BASIC_BLOCK(3U, 5U)
3486 {
3487 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U); // Phi 11
3488 INST(6U, Opcode::Add).s32().Inputs(0U, 1U); // Phi 12
3489 }
3490 BASIC_BLOCK(4U, 5U)
3491 {
3492 INST(8U, Opcode::Sub).s32().Inputs(1U, 0U); // Phi 11
3493 INST(9U, Opcode::Add).s32().Inputs(0U, 1U); // Phi 12
3494 }
3495 BASIC_BLOCK(5U, 1U)
3496 {
3497 INST(11U, Opcode::Phi).s32().Inputs(5U, 8U);
3498 INST(12U, Opcode::Phi).s32().Inputs(6U, 9U);
3499 INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3500 INST(20U, Opcode::SaveState).NoVregs();
3501 INST(14U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 20U);
3502 INST(15U, Opcode::Return).s32().Inputs(13U);
3503 }
3504 }
3505 }
3506
TEST_F(PeepholesTest,TestPhi3)3507 TEST_F(PeepholesTest, TestPhi3)
3508 {
3509 // Peephole rule isn't applied.
3510 // Same types, different inputs.
3511 src_graph::TestPhi3::CREATE(GetGraph());
3512 GetGraph()->RunPass<Peepholes>();
3513 auto graph = CreateEmptyGraph();
3514 out_graph::TestPhi3::CREATE(graph);
3515 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3516 }
3517
SRC_GRAPH(TestPhi4,Graph * graph)3518 SRC_GRAPH(TestPhi4, Graph *graph)
3519 {
3520 GRAPH(graph)
3521 {
3522 PARAMETER(0U, 0U).s32();
3523 PARAMETER(1U, 1U).s32();
3524 BASIC_BLOCK(2U, 3U, 4U)
3525 {
3526 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3527 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3528 }
3529 BASIC_BLOCK(3U, 5U)
3530 {
3531 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3532 }
3533 BASIC_BLOCK(4U, 5U)
3534 {
3535 INST(8U, Opcode::Sub).s32().Inputs(1U, 0U);
3536 }
3537 BASIC_BLOCK(5U, 1U)
3538 {
3539 INST(11U, Opcode::Phi).s16().Inputs(5U, 8U);
3540 INST(12U, Opcode::Phi).s32().Inputs(5U, 8U);
3541 INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3542 INST(20U, Opcode::SaveState).NoVregs();
3543 INST(14U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 20U);
3544 INST(15U, Opcode::Return).s32().Inputs(13U);
3545 }
3546 }
3547 }
3548
OUT_GRAPH(TestPhi4,Graph * graph)3549 OUT_GRAPH(TestPhi4, Graph *graph)
3550 {
3551 GRAPH(graph)
3552 {
3553 PARAMETER(0U, 0U).s32();
3554 PARAMETER(1U, 1U).s32();
3555 BASIC_BLOCK(2U, 3U, 4U)
3556 {
3557 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3558 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3559 }
3560 BASIC_BLOCK(3U, 5U)
3561 {
3562 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3563 }
3564 BASIC_BLOCK(4U, 5U)
3565 {
3566 INST(8U, Opcode::Sub).s32().Inputs(1U, 0U);
3567 }
3568 BASIC_BLOCK(5U, 1U)
3569 {
3570 INST(11U, Opcode::Phi).s16().Inputs(5U, 8U);
3571 INST(12U, Opcode::Phi).s32().Inputs(5U, 8U);
3572 INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3573 INST(20U, Opcode::SaveState).NoVregs();
3574 INST(14U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 20U);
3575 INST(15U, Opcode::Return).s32().Inputs(13U);
3576 }
3577 }
3578 }
3579
TEST_F(PeepholesTest,TestPhi4)3580 TEST_F(PeepholesTest, TestPhi4)
3581 {
3582 // Peephole rule isn't applied.
3583 // Different types, same inputs.
3584 src_graph::TestPhi4::CREATE(GetGraph());
3585 GetGraph()->RunPass<Peepholes>();
3586 auto graph = CreateEmptyGraph();
3587 out_graph::TestPhi4::CREATE(graph);
3588 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3589 }
3590
SRC_GRAPH(TestPhi5,Graph * graph)3591 SRC_GRAPH(TestPhi5, Graph *graph)
3592 {
3593 GRAPH(graph)
3594 {
3595 PARAMETER(0U, 0U).s32();
3596 PARAMETER(1U, 1U).s32();
3597 PARAMETER(17U, 2U).f32();
3598 PARAMETER(18U, 3U).f32();
3599 BASIC_BLOCK(2U, 3U, 4U)
3600 {
3601 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3602 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3603 }
3604 BASIC_BLOCK(3U, 5U)
3605 {
3606 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U); // Phi 11
3607 INST(6U, Opcode::Add).f32().Inputs(18U, 17U); // Phi 12
3608 }
3609 BASIC_BLOCK(4U, 5U)
3610 {
3611 INST(8U, Opcode::Sub).s32().Inputs(1U, 0U); // Phi 11
3612 INST(9U, Opcode::Add).f32().Inputs(18U, 17U); // Phi 12
3613 }
3614 BASIC_BLOCK(5U, 1U)
3615 {
3616 INST(11U, Opcode::Phi).s32().Inputs(5U, 8U);
3617 INST(12U, Opcode::Phi).f32().Inputs(6U, 9U);
3618 INST(13U, Opcode::Cast).f32().SrcType(DataType::INT32).Inputs(11U);
3619 INST(14U, Opcode::Add).f32().Inputs(13U, 12U);
3620 INST(20U, Opcode::SaveState).NoVregs();
3621 INST(15U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 14U, 20U);
3622 INST(16U, Opcode::Return).f32().Inputs(14U);
3623 }
3624 }
3625 }
3626
OUT_GRAPH(TestPhi5,Graph * graph)3627 OUT_GRAPH(TestPhi5, Graph *graph)
3628 {
3629 GRAPH(graph)
3630 {
3631 PARAMETER(0U, 0U).s32();
3632 PARAMETER(1U, 1U).s32();
3633 PARAMETER(17U, 2U).f32();
3634 PARAMETER(18U, 3U).f32();
3635 BASIC_BLOCK(2U, 3U, 4U)
3636 {
3637 INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3638 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3639 }
3640 BASIC_BLOCK(3U, 5U)
3641 {
3642 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U); // Phi 11
3643 INST(6U, Opcode::Add).f32().Inputs(18U, 17U); // Phi 12
3644 }
3645 BASIC_BLOCK(4U, 5U)
3646 {
3647 INST(8U, Opcode::Sub).s32().Inputs(1U, 0U); // Phi 11
3648 INST(9U, Opcode::Add).f32().Inputs(18U, 17U); // Phi 12
3649 }
3650 BASIC_BLOCK(5U, 1U)
3651 {
3652 INST(11U, Opcode::Phi).s32().Inputs(5U, 8U);
3653 INST(12U, Opcode::Phi).f32().Inputs(6U, 9U);
3654 INST(13U, Opcode::Cast).f32().SrcType(DataType::INT32).Inputs(11U);
3655 INST(14U, Opcode::Add).f32().Inputs(13U, 12U);
3656 INST(20U, Opcode::SaveState).NoVregs();
3657 INST(15U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 14U, 20U);
3658 INST(16U, Opcode::Return).f32().Inputs(14U);
3659 }
3660 }
3661 }
3662
TEST_F(PeepholesTest,TestPhi5)3663 TEST_F(PeepholesTest, TestPhi5)
3664 {
3665 // Peephole rule isn't applied.
3666 // Different types, different inputs.
3667 src_graph::TestPhi5::CREATE(GetGraph());
3668 GetGraph()->RunPass<Peepholes>();
3669 auto graph = CreateEmptyGraph();
3670 out_graph::TestPhi5::CREATE(graph);
3671 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3672 }
3673
TEST_F(PeepholesTest,MultiplePeepholeTest)3674 TEST_F(PeepholesTest, MultiplePeepholeTest)
3675 {
3676 GRAPH(GetGraph())
3677 {
3678 CONSTANT(0U, 100U);
3679 CONSTANT(1U, -46L);
3680 CONSTANT(2U, 0U);
3681 BASIC_BLOCK(2U, 3U, 4U)
3682 {
3683 INST(3U, Opcode::Compare).b().SrcType(DataType::Type::INT64).CC(CC_LT).Inputs(1U, 2U);
3684 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3685 }
3686 BASIC_BLOCK(3U, 5U)
3687 {
3688 INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3689 }
3690 BASIC_BLOCK(4U, 5U)
3691 {
3692 INST(8U, Opcode::Add).s32().Inputs(0U, 1U);
3693 }
3694 BASIC_BLOCK(5U, 1U)
3695 {
3696 INST(11U, Opcode::Phi).s32().Inputs(5U, 8U);
3697 INST(16U, Opcode::Return).s32().Inputs(11U);
3698 }
3699 }
3700 GetGraph()->RunPass<Peepholes>();
3701 GetGraph()->RunPass<BranchElimination>();
3702 GetGraph()->RunPass<Cleanup>();
3703 GetGraph()->RunPass<Peepholes>();
3704 #ifndef NDEBUG
3705 GetGraph()->SetLowLevelInstructionsEnabled();
3706 #endif
3707 GetGraph()->RunPass<Lowering>();
3708 GetGraph()->RunPass<Cleanup>();
3709
3710 auto graph = CreateEmptyGraph();
3711 GRAPH(graph)
3712 {
3713 BASIC_BLOCK(5U, 1U)
3714 {
3715 INST(16U, Opcode::ReturnI).s32().Imm(146U);
3716 }
3717 }
3718 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3719 }
3720
TEST_F(PeepholesTest,CompareTest)3721 TEST_F(PeepholesTest, CompareTest)
3722 {
3723 // test case 2
3724 CheckCompare(DataType::UINT32, ConditionCode::CC_LT, ConditionCode::CC_B);
3725 CheckCompare(DataType::UINT32, ConditionCode::CC_LE, ConditionCode::CC_BE);
3726 CheckCompare(DataType::UINT32, ConditionCode::CC_GT, ConditionCode::CC_A);
3727 CheckCompare(DataType::UINT32, ConditionCode::CC_GE, ConditionCode::CC_AE);
3728 CheckCompare(DataType::UINT32, ConditionCode::CC_EQ, ConditionCode::CC_EQ);
3729 CheckCompare(DataType::UINT32, ConditionCode::CC_NE, ConditionCode::CC_NE);
3730
3731 CheckCompare(DataType::INT32, ConditionCode::CC_LT, ConditionCode::CC_LT);
3732 CheckCompare(DataType::INT32, ConditionCode::CC_LE, ConditionCode::CC_LE);
3733 CheckCompare(DataType::INT32, ConditionCode::CC_GT, ConditionCode::CC_GT);
3734 CheckCompare(DataType::INT32, ConditionCode::CC_GE, ConditionCode::CC_GE);
3735 CheckCompare(DataType::INT32, ConditionCode::CC_EQ, ConditionCode::CC_EQ);
3736 CheckCompare(DataType::INT32, ConditionCode::CC_NE, ConditionCode::CC_NE);
3737
3738 CheckCompare(DataType::INT32, ConditionCode::CC_B, ConditionCode::CC_B);
3739 CheckCompare(DataType::INT32, ConditionCode::CC_BE, ConditionCode::CC_BE);
3740 CheckCompare(DataType::INT32, ConditionCode::CC_A, ConditionCode::CC_A);
3741 CheckCompare(DataType::INT32, ConditionCode::CC_AE, ConditionCode::CC_AE);
3742
3743 CheckCompare(DataType::UINT64, ConditionCode::CC_LT, ConditionCode::CC_B);
3744 CheckCompare(DataType::UINT64, ConditionCode::CC_LE, ConditionCode::CC_BE);
3745 CheckCompare(DataType::UINT64, ConditionCode::CC_GT, ConditionCode::CC_A);
3746 CheckCompare(DataType::UINT64, ConditionCode::CC_GE, ConditionCode::CC_AE);
3747 CheckCompare(DataType::UINT64, ConditionCode::CC_EQ, ConditionCode::CC_EQ);
3748 CheckCompare(DataType::UINT64, ConditionCode::CC_NE, ConditionCode::CC_NE);
3749
3750 CheckCompare(DataType::INT64, ConditionCode::CC_LT, ConditionCode::CC_LT);
3751 CheckCompare(DataType::INT64, ConditionCode::CC_LE, ConditionCode::CC_LE);
3752 CheckCompare(DataType::INT64, ConditionCode::CC_GT, ConditionCode::CC_GT);
3753 CheckCompare(DataType::INT64, ConditionCode::CC_GE, ConditionCode::CC_GE);
3754 CheckCompare(DataType::INT64, ConditionCode::CC_EQ, ConditionCode::CC_EQ);
3755 CheckCompare(DataType::INT64, ConditionCode::CC_NE, ConditionCode::CC_NE);
3756
3757 CheckCompare(DataType::INT64, ConditionCode::CC_B, ConditionCode::CC_B);
3758 CheckCompare(DataType::INT64, ConditionCode::CC_BE, ConditionCode::CC_BE);
3759 CheckCompare(DataType::INT64, ConditionCode::CC_A, ConditionCode::CC_A);
3760 CheckCompare(DataType::INT64, ConditionCode::CC_AE, ConditionCode::CC_AE);
3761 }
3762
TEST_F(PeepholesTest,CompareTest1)3763 TEST_F(PeepholesTest, CompareTest1)
3764 {
3765 // applied case 2
3766 GRAPH(GetGraph())
3767 {
3768 CONSTANT(0U, 0U);
3769 PARAMETER(1U, 0U).u32();
3770 PARAMETER(2U, 1U).u32();
3771 BASIC_BLOCK(2U, 1U)
3772 {
3773 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3774 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3775 INST(5U, Opcode::Return).b().Inputs(4U);
3776 }
3777 }
3778 GetGraph()->RunPass<Peepholes>();
3779 GraphChecker(GetGraph()).Check();
3780 auto graph = CreateEmptyGraph();
3781 GRAPH(graph)
3782 {
3783 CONSTANT(0U, 0U);
3784 PARAMETER(1U, 0U).u32();
3785 PARAMETER(2U, 1U).u32();
3786 BASIC_BLOCK(2U, 1U)
3787 {
3788 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3789 INST(4U, Opcode::Compare).b().CC(CC_B).Inputs(1U, 2U);
3790 INST(5U, Opcode::Return).b().Inputs(4U);
3791 }
3792 }
3793 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3794 }
3795
TEST_F(PeepholesTest,CompareTest1Addition0)3796 TEST_F(PeepholesTest, CompareTest1Addition0)
3797 {
3798 // cmp with zero and inputs are signed, compare operands are in normal order (constant is the second operand)
3799 GRAPH(GetGraph())
3800 {
3801 CONSTANT(0U, 0U);
3802 PARAMETER(1U, 1U).u32();
3803 BASIC_BLOCK(2U, 1U)
3804 {
3805 INST(2U, Opcode::Cmp).s32().Inputs(0U, 1U);
3806 INST(3U, Opcode::Compare).b().CC(CC_LT).Inputs(2U, 0U);
3807 INST(4U, Opcode::Return).b().Inputs(3U);
3808 }
3809 }
3810 GetGraph()->RunPass<Peepholes>();
3811 GraphChecker(GetGraph()).Check();
3812 auto graph = CreateEmptyGraph();
3813 GRAPH(graph)
3814 {
3815 CONSTANT(0U, 0U);
3816 PARAMETER(1U, 1U).u32();
3817 BASIC_BLOCK(2U, 1U)
3818 {
3819 INST(2U, Opcode::Cmp).s32().Inputs(0U, 1U);
3820 INST(3U, Opcode::Compare).b().CC(CC_B).Inputs(0U, 1U);
3821 INST(4U, Opcode::Return).b().Inputs(3U);
3822 }
3823 }
3824 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3825 }
3826
TEST_F(PeepholesTest,CompareTest1Addition1)3827 TEST_F(PeepholesTest, CompareTest1Addition1)
3828 {
3829 // cmp inputs are unsigned, compare operands are in reverse order (constant is the first operand)
3830 GRAPH(GetGraph())
3831 {
3832 CONSTANT(0U, 0U);
3833 PARAMETER(1U, 0U).u32();
3834 PARAMETER(2U, 1U).u32();
3835 BASIC_BLOCK(2U, 1U)
3836 {
3837 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3838 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);
3839 INST(5U, Opcode::Return).b().Inputs(4U);
3840 }
3841 }
3842 GetGraph()->RunPass<Peepholes>();
3843 GraphChecker(GetGraph()).Check();
3844 auto graph = CreateEmptyGraph();
3845 GRAPH(graph)
3846 {
3847 CONSTANT(0U, 0U);
3848 PARAMETER(1U, 0U).u32();
3849 PARAMETER(2U, 1U).u32();
3850 BASIC_BLOCK(2U, 1U)
3851 {
3852 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3853 INST(4U, Opcode::Compare).b().CC(CC_A).Inputs(1U, 2U);
3854 INST(5U, Opcode::Return).b().Inputs(4U);
3855 }
3856 }
3857 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3858 }
3859
TEST_F(PeepholesTest,CompareTest1Addition2)3860 TEST_F(PeepholesTest, CompareTest1Addition2)
3861 {
3862 // cmp inputs are signed and compare operands are in normal order
3863 GRAPH(GetGraph())
3864 {
3865 CONSTANT(0U, 0U);
3866 PARAMETER(1U, 0U).s32();
3867 PARAMETER(2U, 1U).s32();
3868 BASIC_BLOCK(2U, 1U)
3869 {
3870 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3871 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3872 INST(5U, Opcode::Return).b().Inputs(4U);
3873 }
3874 }
3875 GetGraph()->RunPass<Peepholes>();
3876 GraphChecker(GetGraph()).Check();
3877 auto graph = CreateEmptyGraph();
3878 GRAPH(graph)
3879 {
3880 CONSTANT(0U, 0U);
3881 PARAMETER(1U, 0U).s32();
3882 PARAMETER(2U, 1U).s32();
3883 BASIC_BLOCK(2U, 1U)
3884 {
3885 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3886 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(1U, 2U);
3887 INST(5U, Opcode::Return).b().Inputs(4U);
3888 }
3889 }
3890 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3891 }
3892
TEST_F(PeepholesTest,CompareTest1Addition3)3893 TEST_F(PeepholesTest, CompareTest1Addition3)
3894 {
3895 // cmp inputs are signed and compare operands are in reverse order
3896 GRAPH(GetGraph())
3897 {
3898 CONSTANT(0U, 0U);
3899 PARAMETER(1U, 0U).s32();
3900 PARAMETER(2U, 1U).s32();
3901 BASIC_BLOCK(2U, 1U)
3902 {
3903 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3904 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);
3905 INST(5U, Opcode::Return).b().Inputs(4U);
3906 }
3907 }
3908 GetGraph()->RunPass<Peepholes>();
3909 GraphChecker(GetGraph()).Check();
3910 auto graph = CreateEmptyGraph();
3911 GRAPH(graph)
3912 {
3913 CONSTANT(0U, 0U);
3914 PARAMETER(1U, 0U).s32();
3915 PARAMETER(2U, 1U).s32();
3916 BASIC_BLOCK(2U, 1U)
3917 {
3918 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3919 INST(4U, Opcode::Compare).b().CC(CC_GT).Inputs(1U, 2U);
3920 INST(5U, Opcode::Return).b().Inputs(4U);
3921 }
3922 }
3923 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3924 }
3925
TEST_F(PeepholesTest,CompareTest2)3926 TEST_F(PeepholesTest, CompareTest2)
3927 {
3928 // not applied, Compare with non zero constant
3929 GRAPH(GetGraph())
3930 {
3931 CONSTANT(0U, 1U);
3932 PARAMETER(1U, 0U).s32();
3933 PARAMETER(2U, 1U).s32();
3934 BASIC_BLOCK(2U, 1U)
3935 {
3936 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3937 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3938 INST(5U, Opcode::Return).b().Inputs(4U);
3939 }
3940 }
3941 GetGraph()->RunPass<Peepholes>();
3942 GraphChecker(GetGraph()).Check();
3943 auto graph = CreateEmptyGraph();
3944 GRAPH(graph)
3945 {
3946 CONSTANT(0U, 1U);
3947 PARAMETER(1U, 0U).s32();
3948 PARAMETER(2U, 1U).s32();
3949 BASIC_BLOCK(2U, 1U)
3950 {
3951 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3952 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3953 INST(5U, Opcode::Return).b().Inputs(4U);
3954 }
3955 }
3956 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3957 }
3958
TEST_F(PeepholesTest,CompareTest3)3959 TEST_F(PeepholesTest, CompareTest3)
3960 {
3961 // not applied, cmp have more than 1 users.
3962 GRAPH(GetGraph())
3963 {
3964 CONSTANT(0U, 1U);
3965 PARAMETER(1U, 0U).s32();
3966 PARAMETER(2U, 1U).s32();
3967 BASIC_BLOCK(2U, 3U, 4U)
3968 {
3969 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3970 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3971 INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
3972 }
3973 BASIC_BLOCK(3U, 1U)
3974 {
3975 INST(6U, Opcode::Return).s32().Inputs(3U);
3976 }
3977 BASIC_BLOCK(4U, 1U)
3978 {
3979 INST(7U, Opcode::Return).s32().Inputs(3U);
3980 }
3981 }
3982 GetGraph()->RunPass<Peepholes>();
3983 GraphChecker(GetGraph()).Check();
3984 auto graph = CreateEmptyGraph();
3985 GRAPH(graph)
3986 {
3987 CONSTANT(0U, 1U);
3988 PARAMETER(1U, 0U).s32();
3989 PARAMETER(2U, 1U).s32();
3990 BASIC_BLOCK(2U, 3U, 4U)
3991 {
3992 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3993 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3994 INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
3995 }
3996 BASIC_BLOCK(3U, 1U)
3997 {
3998 INST(6U, Opcode::Return).s32().Inputs(3U);
3999 }
4000 BASIC_BLOCK(4U, 1U)
4001 {
4002 INST(7U, Opcode::Return).s32().Inputs(3U);
4003 }
4004 }
4005 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4006 }
4007
CompareBoolWithConst(ConditionCode cc,bool input,int cst)4008 static bool CompareBoolWithConst(ConditionCode cc, bool input, int cst)
4009 {
4010 switch (cc) {
4011 case CC_EQ:
4012 return static_cast<int>(input) == cst;
4013 case CC_NE:
4014 return static_cast<int>(input) != cst;
4015 case CC_LT:
4016 return static_cast<int>(input) < cst;
4017 case CC_LE:
4018 return static_cast<int>(input) <= cst;
4019 case CC_GT:
4020 return static_cast<int>(input) > cst;
4021 case CC_GE:
4022 return static_cast<int>(input) >= cst;
4023 case CC_B:
4024 return static_cast<uint64_t>(input) < static_cast<uint64_t>(cst);
4025 case CC_BE:
4026 return static_cast<uint64_t>(input) <= static_cast<uint64_t>(cst);
4027 case CC_A:
4028 return static_cast<uint64_t>(input) > static_cast<uint64_t>(cst);
4029 case CC_AE:
4030 return static_cast<uint64_t>(input) >= static_cast<uint64_t>(cst);
4031 default:
4032 UNREACHABLE();
4033 }
4034 }
4035
TEST_F(PeepholesTest,CompareTest4)4036 TEST_F(PeepholesTest, CompareTest4)
4037 {
4038 for (auto cc : {CC_EQ, CC_NE, CC_LT, CC_LE, CC_GT, CC_GE, CC_B, CC_BE, CC_A, CC_AE}) {
4039 for (auto cst : {-2L, -1L, 0L, 1L, 2L}) {
4040 auto inputTrue = CompareBoolWithConst(cc, true, cst);
4041 auto inputFalse = CompareBoolWithConst(cc, false, cst);
4042 if (inputTrue && inputFalse) {
4043 CheckCompare(cc, cst, {1U}, false);
4044 } else if (!inputTrue && !inputFalse) {
4045 CheckCompare(cc, cst, {0U}, false);
4046 } else if (inputTrue && !inputFalse) {
4047 CheckCompare(cc, cst, std::nullopt, false);
4048 } else {
4049 CheckCompare(cc, cst, std::nullopt, true);
4050 }
4051 }
4052 }
4053 }
4054
TEST_F(PeepholesTest,CompareTestCmpWithZero1)4055 TEST_F(PeepholesTest, CompareTestCmpWithZero1)
4056 {
4057 GRAPH(GetGraph())
4058 {
4059 CONSTANT(0U, 0U);
4060 PARAMETER(1U, 1U).s32();
4061 PARAMETER(2U, 10U).s32();
4062 BASIC_BLOCK(2U, 1U)
4063 {
4064 INST(3U, Opcode::Cast).f64().SrcType(DataType::INT32).Inputs(1U);
4065 INST(4U, Opcode::Cast).f64().SrcType(DataType::INT32).Inputs(2U);
4066 INST(5U, Opcode::Cmp).s32().Inputs(3U, 4U);
4067 INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(5U, 0U);
4068 INST(7U, Opcode::Return).b().Inputs(6U);
4069 }
4070 }
4071 GetGraph()->RunPass<Peepholes>();
4072 GetGraph()->RunPass<Cleanup>();
4073 GraphChecker(GetGraph()).Check();
4074 auto graph = CreateEmptyGraph();
4075 GRAPH(graph)
4076 {
4077 PARAMETER(1U, 1U).s32();
4078 PARAMETER(2U, 10U).s32();
4079 BASIC_BLOCK(2U, 1U)
4080 {
4081 INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(1U, 2U);
4082 INST(7U, Opcode::Return).b().Inputs(6U);
4083 }
4084 }
4085 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4086 }
4087
TEST_F(PeepholesTest,CompareTestCmpWithZero2)4088 TEST_F(PeepholesTest, CompareTestCmpWithZero2)
4089 {
4090 GRAPH(GetGraph())
4091 {
4092 CONSTANT(0U, 0U);
4093 CONSTANT(1U, 10.0F);
4094 PARAMETER(2U, 1U).s32();
4095 BASIC_BLOCK(2U, 1U)
4096 {
4097 INST(3U, Opcode::Cast).f32().SrcType(DataType::INT32).Inputs(2U);
4098 INST(4U, Opcode::Cmp).s32().Inputs(3U, 1U);
4099 INST(5U, Opcode::Compare).b().CC(CC_LT).Inputs(4U, 0U);
4100 INST(6U, Opcode::Return).b().Inputs(5U);
4101 }
4102 }
4103 GetGraph()->RunPass<Peepholes>();
4104 GetGraph()->RunPass<Cleanup>();
4105 GraphChecker(GetGraph()).Check();
4106 auto graph = CreateEmptyGraph();
4107 GRAPH(graph)
4108 {
4109 PARAMETER(2U, 1U).s32();
4110 CONSTANT(7U, 10U);
4111 BASIC_BLOCK(2U, 1U)
4112 {
4113 INST(5U, Opcode::Compare).b().CC(CC_LT).Inputs(2U, 7U);
4114 INST(6U, Opcode::Return).b().Inputs(5U);
4115 }
4116 }
4117 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4118 }
4119
TEST_F(PeepholesTest,CompareTestCmpMultipleUsers)4120 TEST_F(PeepholesTest, CompareTestCmpMultipleUsers)
4121 {
4122 GRAPH(GetGraph())
4123 {
4124 CONSTANT(0U, 0U);
4125 PARAMETER(1U, 0U).s32();
4126 PARAMETER(2U, 1U).s32();
4127 BASIC_BLOCK(2U, 1U)
4128 {
4129 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
4130 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
4131 INST(5U, Opcode::Add).i32().Inputs(3U, 4U);
4132 INST(6U, Opcode::Return).b().Inputs(5U);
4133 }
4134 }
4135 GetGraph()->RunPass<Peepholes>();
4136 GraphChecker(GetGraph()).Check();
4137 auto graph = CreateEmptyGraph();
4138 GRAPH(graph)
4139 {
4140 CONSTANT(0U, 0U);
4141 PARAMETER(1U, 0U).s32();
4142 PARAMETER(2U, 1U).s32();
4143 BASIC_BLOCK(2U, 1U)
4144 {
4145 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
4146 INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(1U, 2U);
4147 INST(5U, Opcode::Add).i32().Inputs(3U, 4U);
4148 INST(6U, Opcode::Return).b().Inputs(5U);
4149 }
4150 }
4151 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4152 }
4153
4154 // cast case 1
TEST_F(PeepholesTest,CastTest1)4155 TEST_F(PeepholesTest, CastTest1)
4156 {
4157 for (int i = 1; i < DataType::ANY; ++i) {
4158 for (int j = 1; j < DataType::ANY; ++j) {
4159 if ((i == DataType::FLOAT32 || i == DataType::FLOAT64) && j >= DataType::BOOL && j <= DataType::INT16) {
4160 continue;
4161 }
4162 CheckCast(static_cast<DataType::Type>(i), static_cast<DataType::Type>(j), i == j);
4163 }
4164 }
4165 }
4166
CastTest2Addition1MainLoop(int i,int j)4167 void PeepholesTest::CastTest2Addition1MainLoop(int i, int j)
4168 {
4169 for (int k = 1; k < DataType::LAST - 5L; ++k) {
4170 if ((i == DataType::FLOAT32 || i == DataType::FLOAT64) && j >= DataType::BOOL && j <= DataType::INT16) {
4171 continue;
4172 }
4173 CheckCast(i, j, k);
4174 }
4175 }
4176
4177 // cast case 2
TEST_F(PeepholesTest,CastTest2Addition1)4178 TEST_F(PeepholesTest, CastTest2Addition1)
4179 {
4180 for (int i = 1; i < DataType::LAST - 5L; ++i) {
4181 for (int j = 1; j < DataType::LAST - 5L; ++j) {
4182 CastTest2Addition1MainLoop(i, j);
4183 }
4184 }
4185 }
4186 // cast case 2
TEST_F(PeepholesTest,CastTest2Addition2)4187 TEST_F(PeepholesTest, CastTest2Addition2)
4188 {
4189 for (int i = DataType::LAST - 5L; i < DataType::ANY; ++i) {
4190 for (int j = DataType::LAST - 5L; j < DataType::ANY; ++j) {
4191 for (int k = DataType::LAST - 5L; k < DataType::ANY; ++k) {
4192 CheckCast(i, j, k);
4193 }
4194 }
4195 }
4196 }
4197
4198 // cast case 1, several casts
TEST_F(PeepholesTest,CastTest3)4199 TEST_F(PeepholesTest, CastTest3)
4200 {
4201 GRAPH(GetGraph())
4202 {
4203 PARAMETER(0U, 0U).s32();
4204 BASIC_BLOCK(2U, 1U)
4205 {
4206 INST(1U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(0U);
4207 INST(2U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(1U);
4208 INST(3U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(2U);
4209 INST(4U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(3U);
4210 INST(5U, Opcode::Return).s32().Inputs(4U);
4211 }
4212 }
4213 auto graph = CreateEmptyGraph();
4214 GRAPH(graph)
4215 {
4216 PARAMETER(0U, 0U).s32();
4217 BASIC_BLOCK(2U, 1U)
4218 {
4219 INST(1U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(0U);
4220 INST(2U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(0U);
4221 INST(3U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(0U);
4222 INST(4U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(0U);
4223 INST(5U, Opcode::Return).s32().Inputs(0U);
4224 }
4225 }
4226 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4227 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4228 }
4229
4230 // Casts from float32/64 to int8/16 don't support.
4231 // cast case 2, several casts
TEST_F(PeepholesTest,DISABLED_CastTest4)4232 TEST_F(PeepholesTest, DISABLED_CastTest4)
4233 {
4234 GRAPH(GetGraph())
4235 {
4236 PARAMETER(0U, 0U).s16();
4237 BASIC_BLOCK(2U, 1U)
4238 {
4239 INST(1U, Opcode::Cast).f32().SrcType(DataType::INT16).Inputs(0U);
4240 INST(2U, Opcode::Cast).s16().SrcType(DataType::FLOAT32).Inputs(1U);
4241 INST(3U, Opcode::Cast).f64().SrcType(DataType::INT16).Inputs(2U);
4242 INST(4U, Opcode::Cast).s16().SrcType(DataType::FLOAT64).Inputs(3U);
4243 INST(5U, Opcode::Return).s16().Inputs(4U);
4244 }
4245 }
4246 auto graph = CreateEmptyGraph();
4247 GRAPH(graph)
4248 {
4249 PARAMETER(0U, 0U).s16();
4250 BASIC_BLOCK(2U, 1U)
4251 {
4252 INST(1U, Opcode::Cast).f32().SrcType(DataType::INT16).Inputs(0U);
4253 INST(2U, Opcode::Cast).s16().SrcType(DataType::FLOAT32).Inputs(1U);
4254 INST(3U, Opcode::Cast).f64().SrcType(DataType::INT16).Inputs(0U);
4255 INST(4U, Opcode::Cast).s16().SrcType(DataType::FLOAT64).Inputs(3U);
4256 INST(5U, Opcode::Return).s16().Inputs(0U);
4257 }
4258 }
4259 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4260 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4261 }
4262
4263 // cast case 3
TEST_F(PeepholesTest,CastTest5)4264 TEST_F(PeepholesTest, CastTest5)
4265 {
4266 GRAPH(GetGraph())
4267 {
4268 PARAMETER(0U, 0U).s32();
4269 CONSTANT(1U, 0x18U);
4270
4271 BASIC_BLOCK(2U, -1L)
4272 {
4273 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
4274 INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
4275 INST(4U, Opcode::Shl).s32().Inputs(3U, 1U);
4276 INST(5U, Opcode::AShr).s32().Inputs(4U, 1U);
4277 INST(6U, Opcode::Return).s32().Inputs(5U);
4278 }
4279 }
4280 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4281 auto graph = CreateEmptyGraph();
4282 GRAPH(graph)
4283 {
4284 PARAMETER(0U, 0U).s32();
4285 CONSTANT(1U, 0x18U);
4286 CONSTANT(7U, 0xffU);
4287
4288 BASIC_BLOCK(2U, -1L)
4289 {
4290 INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
4291 INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
4292 INST(8U, Opcode::And).s32().Inputs(0U, 7U);
4293
4294 INST(4U, Opcode::Shl).s32().Inputs(8U, 1U);
4295 INST(5U, Opcode::AShr).s32().Inputs(4U, 1U);
4296 INST(9U, Opcode::Cast).s8().SrcType(DataType::INT32).Inputs(0U);
4297
4298 INST(6U, Opcode::Return).s32().Inputs(9U);
4299 }
4300 }
4301 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4302 }
4303
TEST_F(PeepholesTest,TrySwapInputsTest)4304 TEST_F(PeepholesTest, TrySwapInputsTest)
4305 {
4306 for (Opcode opc : {Opcode::Add, Opcode::And, Opcode::Or, Opcode::Xor, Opcode::Min, Opcode::Max, Opcode::Mul}) {
4307 auto graph1 = CreateEmptyGraph();
4308 GRAPH(graph1)
4309 {
4310 PARAMETER(0U, 0U).s32();
4311 CONSTANT(1U, 23U);
4312 BASIC_BLOCK(2U, 1U)
4313 {
4314 INST(2U, opc).s32().Inputs(1U, 0U);
4315 INST(3U, Opcode::Return).s32().Inputs(2U);
4316 }
4317 }
4318 ASSERT_TRUE(graph1->RunPass<Peepholes>());
4319 auto graph2 = CreateEmptyGraph();
4320 GRAPH(graph2)
4321 {
4322 PARAMETER(0U, 0U).s32();
4323 CONSTANT(1U, 23U);
4324 BASIC_BLOCK(2U, 1U)
4325 {
4326 INST(2U, opc).s32().Inputs(0U, 1U);
4327 INST(3U, Opcode::Return).s32().Inputs(2U);
4328 }
4329 }
4330 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
4331 }
4332 }
4333
TEST_F(PeepholesTest,ReplaceXorWithNot)4334 TEST_F(PeepholesTest, ReplaceXorWithNot)
4335 {
4336 GRAPH(GetGraph())
4337 {
4338 PARAMETER(0U, 0U).s32();
4339 CONSTANT(1U, -1L);
4340
4341 BASIC_BLOCK(2U, -1L)
4342 {
4343 INST(2U, Opcode::Xor).s32().Inputs(0U, 1U);
4344 INST(3U, Opcode::Xor).s32().Inputs(1U, 0U);
4345 INST(4U, Opcode::Add).s32().Inputs(2U, 3U);
4346 INST(5U, Opcode::Return).s32().Inputs(4U);
4347 }
4348 }
4349 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4350 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4351 auto graph = CreateEmptyGraph();
4352 GRAPH(graph)
4353 {
4354 PARAMETER(0U, 0U).s32();
4355
4356 BASIC_BLOCK(2U, -1L)
4357 {
4358 INST(1U, Opcode::Not).s32().Inputs(0U);
4359 INST(2U, Opcode::Not).s32().Inputs(0U);
4360 INST(3U, Opcode::Add).s32().Inputs(1U, 2U);
4361 INST(4U, Opcode::Return).s32().Inputs(3U);
4362 }
4363 }
4364 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4365 }
4366
TEST_F(PeepholesTest,XorWithZero)4367 TEST_F(PeepholesTest, XorWithZero)
4368 {
4369 GRAPH(GetGraph())
4370 {
4371 PARAMETER(0U, 0U).s32();
4372 CONSTANT(1U, 0U);
4373
4374 BASIC_BLOCK(2U, -1L)
4375 {
4376 INST(2U, Opcode::Xor).s32().Inputs(0U, 1U);
4377 INST(3U, Opcode::Xor).s32().Inputs(1U, 0U);
4378 INST(4U, Opcode::Add).s32().Inputs(2U, 3U);
4379 INST(5U, Opcode::Return).s32().Inputs(4U);
4380 }
4381 }
4382 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4383 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4384 auto graph = CreateEmptyGraph();
4385 GRAPH(graph)
4386 {
4387 PARAMETER(0U, 0U).s32();
4388
4389 BASIC_BLOCK(2U, -1L)
4390 {
4391 INST(3U, Opcode::Add).s32().Inputs(0U, 0U);
4392 INST(4U, Opcode::Return).s32().Inputs(3U);
4393 }
4394 }
4395 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4396 }
4397
SRC_GRAPH(CleanupTrigger,Graph * graph)4398 SRC_GRAPH(CleanupTrigger, Graph *graph)
4399 {
4400 GRAPH(graph)
4401 {
4402 PARAMETER(0U, 0U).u64();
4403 CONSTANT(1U, 1U);
4404 CONSTANT(2U, 2U);
4405 CONSTANT(3U, 3U);
4406 CONSTANT(4U, 4U);
4407 BASIC_BLOCK(2U, 3U, 4U)
4408 {
4409 INST(5U, Opcode::Add).u64().Inputs(1U, 4U);
4410 INST(6U, Opcode::Add).u64().Inputs(2U, 3U);
4411 INST(7U, Opcode::Compare).b().Inputs(0U, 3U);
4412 INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
4413 }
4414 BASIC_BLOCK(3U, 4U) {}
4415 BASIC_BLOCK(4U, -1L)
4416 {
4417 INST(9U, Opcode::Phi).u64().Inputs({{2U, 6U}, {3U, 5U}});
4418 INST(10U, Opcode::Return).u64().Inputs(9U);
4419 }
4420 }
4421 }
4422
OUT_GRAPH(CleanupTrigger,Graph * graph)4423 OUT_GRAPH(CleanupTrigger, Graph *graph)
4424 {
4425 GRAPH(graph)
4426 {
4427 PARAMETER(0U, 0U).u64();
4428 CONSTANT(1U, 1U);
4429 CONSTANT(2U, 2U);
4430 CONSTANT(3U, 3U);
4431 CONSTANT(4U, 4U);
4432 CONSTANT(11U, 5U);
4433 BASIC_BLOCK(2U, 3U, 4U)
4434 {
4435 INST(5U, Opcode::Add).u64().Inputs(1U, 4U);
4436 INST(6U, Opcode::Add).u64().Inputs(2U, 3U);
4437 INST(7U, Opcode::Compare).b().Inputs(0U, 3U);
4438 INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
4439 }
4440 BASIC_BLOCK(3U, 4U) {}
4441 BASIC_BLOCK(4U, -1L)
4442 {
4443 INST(9U, Opcode::Phi).u64().Inputs({{2U, 11U}, {3U, 11U}});
4444 INST(10U, Opcode::Return).u64().Inputs(9U);
4445 }
4446 }
4447 }
4448
TEST_F(PeepholesTest,CleanupTrigger)4449 TEST_F(PeepholesTest, CleanupTrigger)
4450 {
4451 src_graph::CleanupTrigger::CREATE(GetGraph());
4452
4453 GraphChecker(GetGraph()).Check();
4454 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4455
4456 auto graph = CreateEmptyGraph();
4457 out_graph::CleanupTrigger::CREATE(graph);
4458 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4459 }
4460
TEST_F(PeepholesTest,TestAbsUnsigned)4461 TEST_F(PeepholesTest, TestAbsUnsigned)
4462 {
4463 GRAPH(GetGraph())
4464 {
4465 PARAMETER(0U, 1U).u64();
4466 BASIC_BLOCK(2U, -1L)
4467 {
4468 INST(2U, Opcode::Abs).u64().Inputs(0U);
4469 INST(3U, Opcode::Return).u64().Inputs(2U);
4470 }
4471 }
4472 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4473 GraphChecker(GetGraph()).Check();
4474 ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
4475 }
4476
TEST_F(PeepholesTest,SafePoint)4477 TEST_F(PeepholesTest, SafePoint)
4478 {
4479 GRAPH(GetGraph())
4480 {
4481 PARAMETER(0U, 1U).u64();
4482 PARAMETER(1U, 2U).s32();
4483 PARAMETER(2U, 3U).f64();
4484 PARAMETER(3U, 4U).ref();
4485 BASIC_BLOCK(2U, -1L)
4486 {
4487 INST(4U, Opcode::SafePoint).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4488 INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4489 INST(6U, Opcode::CallStatic).u64().InputsAutoType(0U, 1U, 2U, 3U, 5U);
4490 INST(7U, Opcode::Return).u64().Inputs(6U);
4491 }
4492 }
4493 Graph *graphEt = CreateEmptyGraph();
4494 GRAPH(graphEt)
4495 {
4496 PARAMETER(0U, 1U).u64();
4497 PARAMETER(1U, 2U).s32();
4498 PARAMETER(2U, 3U).f64();
4499 PARAMETER(3U, 4U).ref();
4500 BASIC_BLOCK(2U, -1L)
4501 {
4502 INST(4U, Opcode::SafePoint).Inputs(3U).SrcVregs({3U});
4503 INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4504 INST(6U, Opcode::CallStatic).u64().InputsAutoType(0U, 1U, 2U, 3U, 5U);
4505 INST(7U, Opcode::Return).u64().Inputs(6U);
4506 }
4507 }
4508
4509 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4510 GraphChecker(GetGraph()).Check();
4511 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphEt));
4512 }
4513
TEST_F(PeepholesTest,SafePointWithRegMap)4514 TEST_F(PeepholesTest, SafePointWithRegMap)
4515 {
4516 g_options.SetCompilerSafePointsRequireRegMap(true);
4517
4518 GRAPH(GetGraph())
4519 {
4520 PARAMETER(0U, 1U).u64();
4521 PARAMETER(1U, 2U).s32();
4522 PARAMETER(2U, 3U).f64();
4523 PARAMETER(3U, 4U).ref();
4524 BASIC_BLOCK(2U, -1L)
4525 {
4526 INST(4U, Opcode::SafePoint).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4527 INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4528 INST(6U, Opcode::CallStatic).u64().InputsAutoType(0U, 1U, 2U, 3U, 5U);
4529 INST(7U, Opcode::Return).u64().Inputs(6U);
4530 }
4531 }
4532 Graph *graphEt = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
4533 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
4534 GraphChecker(GetGraph()).Check();
4535 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphEt));
4536 }
4537
SRC_GRAPH(ShlShlAddAdd,Graph * graph)4538 SRC_GRAPH(ShlShlAddAdd, Graph *graph)
4539 {
4540 GRAPH(graph)
4541 {
4542 PARAMETER(0U, 0U).i64();
4543 PARAMETER(1U, 1U).i64();
4544 CONSTANT(2U, 16U);
4545 CONSTANT(3U, 17U);
4546 BASIC_BLOCK(2U, -1L)
4547 {
4548 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4549 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4550 INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4551 INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4552 INST(8U, Opcode::Return).i64().Inputs(7U);
4553 }
4554 }
4555 }
4556
OUT_GRAPH(ShlShlAddAdd,Graph * graph)4557 OUT_GRAPH(ShlShlAddAdd, Graph *graph)
4558 {
4559 GRAPH(graph)
4560 {
4561 PARAMETER(0U, 0U).i64();
4562 PARAMETER(1U, 1U).i64();
4563 CONSTANT(2U, 16U);
4564 CONSTANT(3U, 17U);
4565 BASIC_BLOCK(2U, -1L)
4566 {
4567 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4568 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4569 INST(6U, Opcode::Add).i64().Inputs(1U, 4U);
4570 INST(7U, Opcode::Add).i64().Inputs(6U, 5U);
4571 INST(8U, Opcode::Return).i64().Inputs(7U);
4572 }
4573 }
4574 }
4575
SRC_GRAPH(ShlShlAddAdd1,Graph * graph)4576 SRC_GRAPH(ShlShlAddAdd1, Graph *graph)
4577 {
4578 GRAPH(graph)
4579 {
4580 PARAMETER(0U, 0U).i64();
4581 PARAMETER(1U, 1U).i64();
4582 CONSTANT(2U, 16U);
4583 CONSTANT(3U, 17U);
4584 BASIC_BLOCK(2U, -1L)
4585 {
4586 // shl4 !HasSingleUser()
4587 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4588 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4589 INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4590 INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4591 INST(8U, Opcode::Add).i64().Inputs(4U, 7U);
4592 INST(9U, Opcode::Return).i64().Inputs(8U);
4593 }
4594 }
4595 }
4596
SRC_GRAPH(ShlShlAddAdd2,Graph * graph)4597 SRC_GRAPH(ShlShlAddAdd2, Graph *graph)
4598 {
4599 GRAPH(graph)
4600 {
4601 PARAMETER(0U, 0U).i64();
4602 PARAMETER(1U, 1U).i64();
4603 CONSTANT(2U, 16U);
4604 CONSTANT(3U, 17U);
4605 BASIC_BLOCK(2U, -1L)
4606 {
4607 // shl5 !HasSingleUser()
4608 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4609 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4610 INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4611 INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4612 INST(8U, Opcode::Add).i64().Inputs(5U, 7U);
4613 INST(9U, Opcode::Return).i64().Inputs(8U);
4614 }
4615 }
4616 }
4617
SRC_GRAPH(ShlShlAddAdd3,Graph * graph)4618 SRC_GRAPH(ShlShlAddAdd3, Graph *graph)
4619 {
4620 GRAPH(graph)
4621 {
4622 PARAMETER(0U, 0U).i64();
4623 PARAMETER(1U, 1U).i64();
4624 CONSTANT(2U, 16U);
4625 CONSTANT(3U, 17U);
4626 BASIC_BLOCK(2U, -1L)
4627 {
4628 // add6 !HasSingleUser()
4629 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4630 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4631 INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4632 INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4633 INST(8U, Opcode::Add).i64().Inputs(0U, 6U);
4634 INST(9U, Opcode::Return).i64().Inputs(8U);
4635 }
4636 }
4637 }
4638
SRC_GRAPH(ShlShlAddAdd4,Graph * graph)4639 SRC_GRAPH(ShlShlAddAdd4, Graph *graph)
4640 {
4641 GRAPH(graph)
4642 {
4643 PARAMETER(0U, 0U).i64();
4644 PARAMETER(1U, 1U).i64();
4645 CONSTANT(2U, 16U);
4646 CONSTANT(3U, 17U);
4647 BASIC_BLOCK(2U, -1L)
4648 {
4649 // shl4 and shl5 have different input(0).
4650 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4651 INST(5U, Opcode::Shl).i64().Inputs(1U, 3U);
4652 INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4653 INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4654 INST(8U, Opcode::Return).i64().Inputs(7U);
4655 }
4656 }
4657 }
4658
SRC_GRAPH(ShlShlAddAdd5,Graph * graph)4659 SRC_GRAPH(ShlShlAddAdd5, Graph *graph)
4660 {
4661 GRAPH(graph)
4662 {
4663 PARAMETER(0U, 0U).i64();
4664 PARAMETER(1U, 1U).i64();
4665 PARAMETER(2U, 2U).i64();
4666 CONSTANT(3U, 17U);
4667 BASIC_BLOCK(2U, -1L)
4668 {
4669 // shl4->GetInput(1) is not constant.
4670 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4671 INST(5U, Opcode::Shl).i64().Inputs(1U, 3U);
4672 INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4673 INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4674 INST(8U, Opcode::Return).i64().Inputs(7U);
4675 }
4676 }
4677 }
4678
SRC_GRAPH(ShlShlAddAdd6,Graph * graph)4679 SRC_GRAPH(ShlShlAddAdd6, Graph *graph)
4680 {
4681 GRAPH(graph)
4682 {
4683 PARAMETER(0U, 0U).i64();
4684 PARAMETER(1U, 1U).i64();
4685 CONSTANT(2U, 16U);
4686 PARAMETER(3U, 2U).i64();
4687 BASIC_BLOCK(2U, -1L)
4688 {
4689 // shl5->GetInput(1) is not constant.
4690 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4691 INST(5U, Opcode::Shl).i64().Inputs(1U, 3U);
4692 INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4693 INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4694 INST(8U, Opcode::Return).i64().Inputs(7U);
4695 }
4696 }
4697 }
4698
SRC_GRAPH(ShlShlAddAdd7,Graph * graph)4699 SRC_GRAPH(ShlShlAddAdd7, Graph *graph)
4700 {
4701 GRAPH(graph)
4702 {
4703 PARAMETER(0U, 0U).i64();
4704 PARAMETER(1U, 1U).i64();
4705 CONSTANT(2U, 16U);
4706 CONSTANT(3U, 17U);
4707 BASIC_BLOCK(2U, 3U)
4708 {
4709 INST(20U, Opcode::Shl).i64().Inputs(0U, 2U);
4710 INST(21U, Opcode::Shl).i64().Inputs(0U, 3U);
4711 INST(22U, Opcode::Add).i64().Inputs(20U, 21U);
4712 }
4713 BASIC_BLOCK(3U, 4U)
4714 {
4715 INST(30U, Opcode::Add).i64().Inputs(0U, 1U);
4716 }
4717 BASIC_BLOCK(4U, -1L)
4718 {
4719 // add40: input(0) does not dominate input(1)
4720 INST(40U, Opcode::Add).i64().Inputs(30U, 22U);
4721 INST(41U, Opcode::Return).i64().Inputs(40U);
4722 }
4723 }
4724 }
4725
TEST_F(PeepholesTest,ShlShlAddAdd)4726 TEST_F(PeepholesTest, ShlShlAddAdd)
4727 {
4728 src_graph::ShlShlAddAdd::CREATE(GetGraph());
4729 Graph *graphPeepholed = CreateEmptyGraph();
4730 out_graph::ShlShlAddAdd::CREATE(graphPeepholed);
4731
4732 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4733 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4734 GraphChecker(GetGraph()).Check();
4735 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphPeepholed));
4736
4737 // Not optimizable cases
4738 Graph *graphNotOptimizable = CreateEmptyGraph();
4739 src_graph::ShlShlAddAdd1::CREATE(graphNotOptimizable);
4740 ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4741
4742 graphNotOptimizable = CreateEmptyGraph();
4743 src_graph::ShlShlAddAdd2::CREATE(graphNotOptimizable);
4744 ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4745
4746 graphNotOptimizable = CreateEmptyGraph();
4747 src_graph::ShlShlAddAdd3::CREATE(graphNotOptimizable);
4748 ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4749
4750 graphNotOptimizable = CreateEmptyGraph();
4751 src_graph::ShlShlAddAdd4::CREATE(graphNotOptimizable);
4752 ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4753
4754 graphNotOptimizable = CreateEmptyGraph();
4755 src_graph::ShlShlAddAdd5::CREATE(graphNotOptimizable);
4756 ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4757
4758 graphNotOptimizable = CreateEmptyGraph();
4759 src_graph::ShlShlAddAdd6::CREATE(graphNotOptimizable);
4760 ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4761
4762 graphNotOptimizable = CreateEmptyGraph();
4763 src_graph::ShlShlAddAdd7::CREATE(graphNotOptimizable);
4764 ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4765 }
4766
TEST_F(PeepholesTest,ShlShlAddSub)4767 TEST_F(PeepholesTest, ShlShlAddSub)
4768 {
4769 GRAPH(GetGraph())
4770 {
4771 PARAMETER(0U, 0U).i64();
4772 PARAMETER(1U, 1U).i64();
4773 CONSTANT(2U, 16U);
4774 CONSTANT(3U, 17U);
4775 BASIC_BLOCK(2U, -1L)
4776 {
4777 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4778 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4779 INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4780 INST(7U, Opcode::Sub).i64().Inputs(1U, 6U);
4781 INST(8U, Opcode::Return).i64().Inputs(7U);
4782 }
4783 }
4784 Graph *graphPeepholed = CreateEmptyGraph();
4785 GRAPH(graphPeepholed)
4786 {
4787 PARAMETER(0U, 0U).i64();
4788 PARAMETER(1U, 1U).i64();
4789 CONSTANT(2U, 16U);
4790 CONSTANT(3U, 17U);
4791 BASIC_BLOCK(2U, -1L)
4792 {
4793 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4794 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4795 INST(6U, Opcode::Sub).i64().Inputs(1U, 4U);
4796 INST(7U, Opcode::Sub).i64().Inputs(6U, 5U);
4797 INST(8U, Opcode::Return).i64().Inputs(7U);
4798 }
4799 }
4800
4801 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4802 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4803 GraphChecker(GetGraph()).Check();
4804 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphPeepholed));
4805 }
4806
TEST_F(PeepholesTest,ShlShlSubAdd)4807 TEST_F(PeepholesTest, ShlShlSubAdd)
4808 {
4809 GRAPH(GetGraph())
4810 {
4811 PARAMETER(0U, 0U).i64();
4812 PARAMETER(1U, 1U).i64();
4813 CONSTANT(2U, 16U);
4814 CONSTANT(3U, 17U);
4815 BASIC_BLOCK(2U, -1L)
4816 {
4817 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4818 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4819 INST(6U, Opcode::Sub).i64().Inputs(4U, 5U);
4820 INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4821 INST(8U, Opcode::Return).i64().Inputs(7U);
4822 }
4823 }
4824 Graph *graphPeepholed = CreateEmptyGraph();
4825 GRAPH(graphPeepholed)
4826 {
4827 PARAMETER(0U, 0U).i64();
4828 PARAMETER(1U, 1U).i64();
4829 CONSTANT(2U, 16U);
4830 CONSTANT(3U, 17U);
4831 BASIC_BLOCK(2U, -1L)
4832 {
4833 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4834 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4835 INST(6U, Opcode::Add).i64().Inputs(1U, 4U);
4836 INST(7U, Opcode::Sub).i64().Inputs(6U, 5U);
4837 INST(8U, Opcode::Return).i64().Inputs(7U);
4838 }
4839 }
4840
4841 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4842 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4843 GraphChecker(GetGraph()).Check();
4844 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphPeepholed));
4845 }
4846
TEST_F(PeepholesTest,ShlShlSubSub)4847 TEST_F(PeepholesTest, ShlShlSubSub)
4848 {
4849 GRAPH(GetGraph())
4850 {
4851 PARAMETER(0U, 0U).i64();
4852 PARAMETER(1U, 1U).i64();
4853 CONSTANT(2U, 16U);
4854 CONSTANT(3U, 17U);
4855 BASIC_BLOCK(2U, -1L)
4856 {
4857 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4858 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4859 INST(6U, Opcode::Sub).i64().Inputs(4U, 5U);
4860 INST(7U, Opcode::Sub).i64().Inputs(1U, 6U);
4861 INST(8U, Opcode::Return).i64().Inputs(7U);
4862 }
4863 }
4864 Graph *graphPeepholed = CreateEmptyGraph();
4865 GRAPH(graphPeepholed)
4866 {
4867 PARAMETER(0U, 0U).i64();
4868 PARAMETER(1U, 1U).i64();
4869 CONSTANT(2U, 16U);
4870 CONSTANT(3U, 17U);
4871 BASIC_BLOCK(2U, -1L)
4872 {
4873 INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4874 INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4875 INST(6U, Opcode::Sub).i64().Inputs(1U, 4U);
4876 INST(7U, Opcode::Add).i64().Inputs(6U, 5U);
4877 INST(8U, Opcode::Return).i64().Inputs(7U);
4878 }
4879 }
4880
4881 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4882 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4883 GraphChecker(GetGraph()).Check();
4884 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphPeepholed));
4885 }
4886
TEST_F(PeepholesTest,CompareAndWithZero)4887 TEST_F(PeepholesTest, CompareAndWithZero)
4888 {
4889 CheckCompareFoldIntoTest(0U, CC_EQ, true, CC_TST_EQ);
4890 CheckCompareFoldIntoTest(0U, CC_NE, true, CC_TST_NE);
4891
4892 CheckCompareFoldIntoTest(1U, CC_EQ, false);
4893 CheckCompareFoldIntoTest(2U, CC_NE, false);
4894
4895 // check comparision with zero for all CCs except CC_EQ and CC_NE
4896 for (int cc = CC_LT; cc <= CC_LAST; ++cc) {
4897 CheckCompareFoldIntoTest(0U, static_cast<ConditionCode>(cc), false);
4898 }
4899 }
4900
TEST_F(PeepholesTest,IfAndComparedWithZero)4901 TEST_F(PeepholesTest, IfAndComparedWithZero)
4902 {
4903 CheckIfAndZeroFoldIntoIfTest(0U, CC_EQ, true, CC_TST_EQ);
4904 CheckIfAndZeroFoldIntoIfTest(0U, CC_NE, true, CC_TST_NE);
4905
4906 CheckIfAndZeroFoldIntoIfTest(1U, CC_EQ, false);
4907 CheckIfAndZeroFoldIntoIfTest(2U, CC_NE, false);
4908
4909 // check comparision with zero for all CCs except CC_EQ and CC_NE
4910 for (int cc = CC_LT; cc <= CC_LAST; ++cc) {
4911 CheckCompareFoldIntoTest(0U, static_cast<ConditionCode>(cc), false);
4912 }
4913 }
4914
TEST_F(PeepholesTest,CompareLenArrayWithZero)4915 TEST_F(PeepholesTest, CompareLenArrayWithZero)
4916 {
4917 CheckCompareLenArrayWithZeroTest(0U, CC_GE, true);
4918 CheckCompareLenArrayWithZeroTest(0U, CC_LT, false);
4919 CheckCompareLenArrayWithZeroTest(0U, CC_LE, std::nullopt);
4920 CheckCompareLenArrayWithZeroTest(1U, CC_GE, std::nullopt);
4921 CheckCompareLenArrayWithZeroTest(1U, CC_LT, std::nullopt);
4922 }
4923
TEST_F(PeepholesTest,CompareLenArrayWithZeroSwapped)4924 TEST_F(PeepholesTest, CompareLenArrayWithZeroSwapped)
4925 {
4926 CheckCompareLenArrayWithZeroTest(0U, CC_LE, true, true);
4927 CheckCompareLenArrayWithZeroTest(0U, CC_GT, false, true);
4928 CheckCompareLenArrayWithZeroTest(0U, CC_GE, std::nullopt, true);
4929 CheckCompareLenArrayWithZeroTest(1U, CC_LE, std::nullopt, true);
4930 CheckCompareLenArrayWithZeroTest(1U, CC_GT, std::nullopt, true);
4931 }
4932
TEST_F(PeepholesTest,TestEqualInputs)4933 TEST_F(PeepholesTest, TestEqualInputs)
4934 {
4935 GRAPH(GetGraph())
4936 {
4937 PARAMETER(0U, 0U).u64();
4938
4939 BASIC_BLOCK(2U, -1L)
4940 {
4941 INST(1U, Opcode::Compare).b().CC(CC_TST_EQ).Inputs(0U, 0U);
4942 INST(2U, Opcode::Compare).b().CC(CC_TST_NE).Inputs(0U, 0U);
4943 INST(3U, Opcode::SaveState).NoVregs();
4944 INST(4U, Opcode::CallStatic).b().InputsAutoType(1U, 2U, 3U);
4945 INST(5U, Opcode::ReturnVoid);
4946 }
4947 }
4948 Graph *graphPeepholed = CreateEmptyGraph();
4949 GRAPH(graphPeepholed)
4950 {
4951 PARAMETER(0U, 0U).u64();
4952 CONSTANT(1U, 0U).s64();
4953
4954 BASIC_BLOCK(2U, -1L)
4955 {
4956 INST(2U, Opcode::Compare).b().CC(CC_EQ).Inputs(0U, 1U);
4957 INST(3U, Opcode::Compare).b().CC(CC_NE).Inputs(0U, 1U);
4958 INST(4U, Opcode::SaveState).NoVregs();
4959 INST(5U, Opcode::CallStatic).b().InputsAutoType(2U, 3U, 4U);
4960 INST(6U, Opcode::ReturnVoid);
4961 }
4962 }
4963
4964 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4965 GraphChecker(GetGraph()).Check();
4966 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphPeepholed));
4967 }
4968
SRC_GRAPH(AndWithCast,Graph * graph)4969 SRC_GRAPH(AndWithCast, Graph *graph)
4970 {
4971 GRAPH(graph)
4972 {
4973 PARAMETER(0U, 0U).i64();
4974 PARAMETER(1U, 1U).i32();
4975 CONSTANT(2U, 0xFFFFFFFFU);
4976 CONSTANT(3U, 0xFFFFU);
4977 CONSTANT(4U, 0xFFU);
4978 CONSTANT(5U, 0xF7U);
4979
4980 BASIC_BLOCK(2U, -1L)
4981 {
4982 INST(10U, Opcode::And).i32().Inputs(1U, 2U);
4983 INST(11U, Opcode::And).i32().Inputs(1U, 3U);
4984 INST(12U, Opcode::And).i32().Inputs(1U, 4U);
4985 INST(13U, Opcode::And).i32().Inputs(1U, 5U);
4986
4987 INST(22U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(10U);
4988 INST(23U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(11U);
4989 INST(24U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(12U);
4990 INST(25U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(13U);
4991
4992 INST(26U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(10U);
4993 INST(27U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(11U);
4994 INST(28U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(12U);
4995 INST(29U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(13U);
4996
4997 INST(30U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(10U);
4998 INST(31U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(11U);
4999 INST(32U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(12U);
5000 INST(33U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(13U);
5001
5002 INST(34U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(10U);
5003 INST(35U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(11U);
5004 INST(36U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(12U);
5005 INST(37U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(13U);
5006
5007 INST(38U, Opcode::ReturnVoid).v0id();
5008 }
5009 }
5010 }
5011
OUT_GRAPH(AndWithCast,Graph * graph)5012 OUT_GRAPH(AndWithCast, Graph *graph)
5013 {
5014 GRAPH(graph)
5015 {
5016 PARAMETER(0U, 0U).i64();
5017 PARAMETER(1U, 1U).i32();
5018 CONSTANT(2U, 0xFFFFFFFFU);
5019 CONSTANT(3U, 0xFFFFU);
5020 CONSTANT(4U, 0xFFU);
5021 CONSTANT(5U, 0xF7U);
5022
5023 BASIC_BLOCK(2U, -1L)
5024 {
5025 INST(10U, Opcode::And).i32().Inputs(1U, 2U);
5026 INST(11U, Opcode::And).i32().Inputs(1U, 3U);
5027 INST(12U, Opcode::And).i32().Inputs(1U, 4U);
5028 INST(13U, Opcode::And).i32().Inputs(1U, 5U);
5029
5030 INST(22U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(1U);
5031 INST(23U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(1U);
5032 INST(24U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(12U);
5033 INST(25U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(13U);
5034
5035 INST(26U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(1U);
5036 INST(27U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(1U);
5037 INST(28U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(12U);
5038 INST(29U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(13U);
5039
5040 INST(30U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(1U);
5041 INST(31U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(1U);
5042 INST(32U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(1U);
5043 INST(33U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(13U);
5044
5045 INST(34U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(1U);
5046 INST(35U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(1U);
5047 INST(36U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(1U);
5048 INST(37U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(13U);
5049
5050 INST(38U, Opcode::ReturnVoid).v0id();
5051 }
5052 }
5053 }
5054
TEST_F(PeepholesTest,AndWithCast)5055 TEST_F(PeepholesTest, AndWithCast)
5056 {
5057 auto graph = CreateEmptyGraph();
5058 src_graph::AndWithCast::CREATE(graph);
5059
5060 auto graphExpected = CreateEmptyGraph();
5061 out_graph::AndWithCast::CREATE(graphExpected);
5062 ASSERT_TRUE(graph->RunPass<Peepholes>());
5063 ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5064 }
5065
SRC_GRAPH(AndWithStore,Graph * graph)5066 SRC_GRAPH(AndWithStore, Graph *graph)
5067 {
5068 GRAPH(graph)
5069 {
5070 PARAMETER(0U, 0U).ptr();
5071 PARAMETER(1U, 1U).u64();
5072 CONSTANT(2U, 0xFFFFFFFFU);
5073 CONSTANT(3U, 0xFFFFU);
5074 CONSTANT(4U, 0xFFU);
5075 CONSTANT(5U, 0xF7U);
5076
5077 BASIC_BLOCK(2U, -1L)
5078 {
5079 INST(6U, Opcode::And).i32().Inputs(1U, 2U);
5080 INST(7U, Opcode::And).i32().Inputs(1U, 3U);
5081 INST(8U, Opcode::And).i32().Inputs(1U, 4U);
5082 INST(9U, Opcode::And).i32().Inputs(1U, 5U);
5083
5084 INST(10U, Opcode::Store).i32().Inputs(0U, 1U, 6U);
5085 INST(11U, Opcode::Store).i32().Inputs(0U, 1U, 7U);
5086 INST(12U, Opcode::Store).i32().Inputs(0U, 1U, 8U);
5087 INST(13U, Opcode::Store).i32().Inputs(0U, 1U, 9U);
5088
5089 INST(14U, Opcode::Store).u32().Inputs(0U, 1U, 6U);
5090 INST(15U, Opcode::Store).u32().Inputs(0U, 1U, 7U);
5091 INST(16U, Opcode::Store).u32().Inputs(0U, 1U, 8U);
5092 INST(17U, Opcode::Store).u32().Inputs(0U, 1U, 9U);
5093
5094 INST(18U, Opcode::Store).i16().Inputs(0U, 1U, 6U);
5095 INST(19U, Opcode::Store).i16().Inputs(0U, 1U, 7U);
5096 INST(20U, Opcode::Store).i16().Inputs(0U, 1U, 8U);
5097 INST(21U, Opcode::Store).i16().Inputs(0U, 1U, 9U);
5098
5099 INST(22U, Opcode::Store).u16().Inputs(0U, 1U, 6U);
5100 INST(23U, Opcode::Store).u16().Inputs(0U, 1U, 7U);
5101 INST(24U, Opcode::Store).u16().Inputs(0U, 1U, 8U);
5102 INST(25U, Opcode::Store).u16().Inputs(0U, 1U, 9U);
5103
5104 INST(26U, Opcode::Store).i8().Inputs(0U, 1U, 6U);
5105 INST(27U, Opcode::Store).i8().Inputs(0U, 1U, 7U);
5106 INST(28U, Opcode::Store).i8().Inputs(0U, 1U, 8U);
5107 INST(29U, Opcode::Store).i8().Inputs(0U, 1U, 9U);
5108
5109 INST(30U, Opcode::Store).u8().Inputs(0U, 1U, 6U);
5110 INST(31U, Opcode::Store).u8().Inputs(0U, 1U, 7U);
5111 INST(32U, Opcode::Store).u8().Inputs(0U, 1U, 8U);
5112 INST(33U, Opcode::Store).u8().Inputs(0U, 1U, 9U);
5113
5114 INST(34U, Opcode::ReturnVoid).v0id();
5115 }
5116 }
5117 }
5118
OUT_GRAPH(AndWithStore,Graph * graph)5119 OUT_GRAPH(AndWithStore, Graph *graph)
5120 {
5121 GRAPH(graph)
5122 {
5123 PARAMETER(0U, 0U).ptr();
5124 PARAMETER(1U, 1U).u64();
5125 CONSTANT(2U, 0xFFFFFFFFU);
5126 CONSTANT(3U, 0xFFFFU);
5127 CONSTANT(4U, 0xFFU);
5128 CONSTANT(5U, 0xF7U);
5129
5130 BASIC_BLOCK(2U, -1L)
5131 {
5132 INST(6U, Opcode::And).i32().Inputs(1U, 2U);
5133 INST(7U, Opcode::And).i32().Inputs(1U, 3U);
5134 INST(8U, Opcode::And).i32().Inputs(1U, 4U);
5135 INST(9U, Opcode::And).i32().Inputs(1U, 5U);
5136
5137 INST(10U, Opcode::Store).i32().Inputs(0U, 1U, 1U);
5138 INST(11U, Opcode::Store).i32().Inputs(0U, 1U, 7U);
5139 INST(12U, Opcode::Store).i32().Inputs(0U, 1U, 8U);
5140 INST(13U, Opcode::Store).i32().Inputs(0U, 1U, 9U);
5141
5142 INST(14U, Opcode::Store).u32().Inputs(0U, 1U, 1U);
5143 INST(15U, Opcode::Store).u32().Inputs(0U, 1U, 7U);
5144 INST(16U, Opcode::Store).u32().Inputs(0U, 1U, 8U);
5145 INST(17U, Opcode::Store).u32().Inputs(0U, 1U, 9U);
5146
5147 INST(18U, Opcode::Store).i16().Inputs(0U, 1U, 1U);
5148 INST(19U, Opcode::Store).i16().Inputs(0U, 1U, 1U);
5149 INST(20U, Opcode::Store).i16().Inputs(0U, 1U, 8U);
5150 INST(21U, Opcode::Store).i16().Inputs(0U, 1U, 9U);
5151
5152 INST(22U, Opcode::Store).u16().Inputs(0U, 1U, 1U);
5153 INST(23U, Opcode::Store).u16().Inputs(0U, 1U, 1U);
5154 INST(24U, Opcode::Store).u16().Inputs(0U, 1U, 8U);
5155 INST(25U, Opcode::Store).u16().Inputs(0U, 1U, 9U);
5156
5157 INST(26U, Opcode::Store).i8().Inputs(0U, 1U, 1U);
5158 INST(27U, Opcode::Store).i8().Inputs(0U, 1U, 1U);
5159 INST(28U, Opcode::Store).i8().Inputs(0U, 1U, 1U);
5160 INST(29U, Opcode::Store).i8().Inputs(0U, 1U, 9U);
5161
5162 INST(30U, Opcode::Store).u8().Inputs(0U, 1U, 1U);
5163 INST(31U, Opcode::Store).u8().Inputs(0U, 1U, 1U);
5164 INST(32U, Opcode::Store).u8().Inputs(0U, 1U, 1U);
5165 INST(33U, Opcode::Store).u8().Inputs(0U, 1U, 9U);
5166
5167 INST(34U, Opcode::ReturnVoid).v0id();
5168 }
5169 }
5170 }
5171
TEST_F(PeepholesTest,AndWithStore)5172 TEST_F(PeepholesTest, AndWithStore)
5173 {
5174 auto graph = CreateEmptyGraph();
5175 src_graph::AndWithStore::CREATE(graph);
5176 auto graphExpected = CreateEmptyGraph();
5177 out_graph::AndWithStore::CREATE(graphExpected);
5178 ASSERT_TRUE(graph->RunPass<Peepholes>());
5179 ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5180 }
5181
SRC_GRAPH(CastWithStore,Graph * graph)5182 SRC_GRAPH(CastWithStore, Graph *graph)
5183 {
5184 GRAPH(graph)
5185 {
5186 PARAMETER(0U, 0U).ptr();
5187 PARAMETER(1U, 1U).i64();
5188 PARAMETER(2U, 2U).i32();
5189
5190 BASIC_BLOCK(2U, -1L)
5191 {
5192 INST(6U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(1U);
5193 INST(7U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(2U);
5194 INST(8U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(2U);
5195
5196 INST(9U, Opcode::Store).i32().Inputs(0U, 1U, 6U);
5197 INST(10U, Opcode::Store).i32().Inputs(0U, 1U, 7U);
5198 INST(11U, Opcode::Store).i32().Inputs(0U, 1U, 8U);
5199
5200 INST(12U, Opcode::Store).u32().Inputs(0U, 1U, 6U);
5201 INST(13U, Opcode::Store).u32().Inputs(0U, 1U, 7U);
5202 INST(14U, Opcode::Store).u32().Inputs(0U, 1U, 8U);
5203
5204 INST(15U, Opcode::Store).i16().Inputs(0U, 1U, 6U);
5205 INST(16U, Opcode::Store).i16().Inputs(0U, 1U, 7U);
5206 INST(17U, Opcode::Store).i16().Inputs(0U, 1U, 8U);
5207
5208 INST(18U, Opcode::Store).u16().Inputs(0U, 1U, 6U);
5209 INST(19U, Opcode::Store).u16().Inputs(0U, 1U, 7U);
5210 INST(20U, Opcode::Store).u16().Inputs(0U, 1U, 8U);
5211
5212 INST(21U, Opcode::Store).i8().Inputs(0U, 1U, 6U);
5213 INST(22U, Opcode::Store).i8().Inputs(0U, 1U, 7U);
5214 INST(23U, Opcode::Store).i8().Inputs(0U, 1U, 8U);
5215
5216 INST(24U, Opcode::Store).u8().Inputs(0U, 1U, 6U);
5217 INST(25U, Opcode::Store).u8().Inputs(0U, 1U, 7U);
5218 INST(26U, Opcode::Store).u8().Inputs(0U, 1U, 8U);
5219
5220 INST(27U, Opcode::ReturnVoid).v0id();
5221 }
5222 }
5223 }
5224
OUT_GRAPH(CastWithStore,Graph * graph)5225 OUT_GRAPH(CastWithStore, Graph *graph)
5226 {
5227 GRAPH(graph)
5228 {
5229 PARAMETER(0U, 0U).ptr();
5230 PARAMETER(1U, 1U).i64();
5231 PARAMETER(2U, 2U).i32();
5232
5233 BASIC_BLOCK(2U, -1L)
5234 {
5235 INST(6U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(1U);
5236 INST(7U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(2U);
5237 INST(8U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(2U);
5238
5239 INST(9U, Opcode::Store).i32().Inputs(0U, 1U, 1U);
5240 INST(10U, Opcode::Store).i32().Inputs(0U, 1U, 7U);
5241 INST(11U, Opcode::Store).i32().Inputs(0U, 1U, 8U);
5242
5243 INST(12U, Opcode::Store).u32().Inputs(0U, 1U, 1U);
5244 INST(13U, Opcode::Store).u32().Inputs(0U, 1U, 7U);
5245 INST(14U, Opcode::Store).u32().Inputs(0U, 1U, 8U);
5246
5247 INST(15U, Opcode::Store).i16().Inputs(0U, 1U, 1U);
5248 INST(16U, Opcode::Store).i16().Inputs(0U, 1U, 2U);
5249 INST(17U, Opcode::Store).i16().Inputs(0U, 1U, 8U);
5250
5251 INST(18U, Opcode::Store).u16().Inputs(0U, 1U, 1U);
5252 INST(19U, Opcode::Store).u16().Inputs(0U, 1U, 2U);
5253 INST(20U, Opcode::Store).u16().Inputs(0U, 1U, 8U);
5254
5255 INST(21U, Opcode::Store).i8().Inputs(0U, 1U, 1U);
5256 INST(22U, Opcode::Store).i8().Inputs(0U, 1U, 2U);
5257 INST(23U, Opcode::Store).i8().Inputs(0U, 1U, 2U);
5258
5259 INST(24U, Opcode::Store).u8().Inputs(0U, 1U, 1U);
5260 INST(25U, Opcode::Store).u8().Inputs(0U, 1U, 2U);
5261 INST(26U, Opcode::Store).u8().Inputs(0U, 1U, 2U);
5262
5263 INST(27U, Opcode::ReturnVoid).v0id();
5264 }
5265 }
5266 }
5267
TEST_F(PeepholesTest,CastWithStore)5268 TEST_F(PeepholesTest, CastWithStore)
5269 {
5270 auto graph = CreateEmptyGraph();
5271 src_graph::CastWithStore::CREATE(graph);
5272 auto graphExpected = CreateEmptyGraph();
5273 out_graph::CastWithStore::CREATE(graphExpected);
5274 ASSERT_TRUE(graph->RunPass<Peepholes>());
5275 ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5276 }
5277
TEST_F(PeepholesTest,CastWithStoreSignMismatch)5278 TEST_F(PeepholesTest, CastWithStoreSignMismatch)
5279 {
5280 auto graph = CreateEmptyGraph();
5281 GRAPH(graph)
5282 {
5283 PARAMETER(0U, 0U).ptr();
5284 PARAMETER(1U, 1U).i64();
5285 PARAMETER(2U, 2U).u8();
5286
5287 BASIC_BLOCK(2U, -1L)
5288 {
5289 INST(3U, Opcode::Cast).i32().SrcType(DataType::INT8).Inputs(2U);
5290 INST(4U, Opcode::Store).i32().Inputs(0U, 1U, 3U);
5291 INST(5U, Opcode::ReturnVoid).v0id();
5292 }
5293 }
5294 #ifndef NDEBUG
5295 ASSERT_DEATH(graph->RunPass<Peepholes>(), "");
5296 #else
5297 ASSERT_FALSE(graph->RunPass<Peepholes>());
5298 #endif
5299 }
5300
TEST_F(PeepholesTest,CastWithStoreTypeMismatch)5301 TEST_F(PeepholesTest, CastWithStoreTypeMismatch)
5302 {
5303 auto graph = CreateEmptyGraph();
5304 GRAPH(graph)
5305 {
5306 PARAMETER(0U, 0U).ptr();
5307 PARAMETER(1U, 1U).i64();
5308 PARAMETER(2U, 2U).i16();
5309
5310 BASIC_BLOCK(2U, -1L)
5311 {
5312 INST(3U, Opcode::Cast).i32().SrcType(DataType::INT8).Inputs(2U);
5313 INST(4U, Opcode::Store).i32().Inputs(0U, 1U, 3U);
5314 INST(5U, Opcode::ReturnVoid).v0id();
5315 }
5316 }
5317 #ifndef NDEBUG
5318 ASSERT_DEATH(graph->RunPass<Peepholes>(), "");
5319 #else
5320 ASSERT_FALSE(graph->RunPass<Peepholes>());
5321 #endif
5322 }
5323
TEST_F(PeepholesTest,CastI64ToU16)5324 TEST_F(PeepholesTest, CastI64ToU16)
5325 {
5326 auto graph = CreateEmptyGraph();
5327 GRAPH(graph)
5328 {
5329 PARAMETER(0U, 0U).i64();
5330 CONSTANT(2U, 0xFFFFU);
5331
5332 BASIC_BLOCK(2U, -1L)
5333 {
5334 INST(3U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(0U);
5335 INST(4U, Opcode::And).i32().Inputs(3U, 2U);
5336 INST(5U, Opcode::Return).i32().Inputs(4U);
5337 }
5338 }
5339
5340 auto graphExpected = CreateEmptyGraph();
5341 GRAPH(graphExpected)
5342 {
5343 PARAMETER(0U, 0U).i64();
5344
5345 BASIC_BLOCK(2U, -1L)
5346 {
5347 INST(6U, Opcode::Cast).u16().SrcType(DataType::INT64).Inputs(0U);
5348 INST(5U, Opcode::Return).i32().Inputs(6U);
5349 }
5350 }
5351 ASSERT_TRUE(graph->RunPass<Peepholes>());
5352 graph->RunPass<Cleanup>();
5353 ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5354 }
5355
TEST_F(PeepholesTest,CastI8ToU16)5356 TEST_F(PeepholesTest, CastI8ToU16)
5357 {
5358 auto graph = CreateEmptyGraph();
5359 GRAPH(graph)
5360 {
5361 PARAMETER(0U, 0U).i8();
5362 CONSTANT(2U, 0xFFFFU);
5363
5364 BASIC_BLOCK(2U, -1L)
5365 {
5366 INST(3U, Opcode::Cast).i32().SrcType(DataType::INT8).Inputs(0U);
5367 INST(4U, Opcode::And).i32().Inputs(3U, 2U);
5368 INST(5U, Opcode::Return).i32().Inputs(4U);
5369 }
5370 }
5371
5372 auto graphExpected = CreateEmptyGraph();
5373 GRAPH(graphExpected)
5374 {
5375 PARAMETER(0U, 0U).i8();
5376
5377 BASIC_BLOCK(2U, -1L)
5378 {
5379 INST(6U, Opcode::Cast).u16().SrcType(DataType::INT8).Inputs(0U);
5380 INST(5U, Opcode::Return).i32().Inputs(6U);
5381 }
5382 }
5383 ASSERT_TRUE(graph->RunPass<Peepholes>());
5384 graph->RunPass<Cleanup>();
5385 ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5386 }
5387
TEST_F(PeepholesTest,CastI64ToB)5388 TEST_F(PeepholesTest, CastI64ToB)
5389 {
5390 auto graph = CreateEmptyGraph();
5391 GRAPH(graph)
5392 {
5393 PARAMETER(0U, 0U).i64();
5394
5395 BASIC_BLOCK(2U, -1L)
5396 {
5397 INST(1U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(0U);
5398 INST(2U, Opcode::Cast).b().SrcType(DataType::INT32).Inputs(1U);
5399 INST(3U, Opcode::Return).b().Inputs(2U);
5400 }
5401 }
5402
5403 auto graphExpected = CreateEmptyGraph();
5404 GRAPH(graphExpected)
5405 {
5406 PARAMETER(0U, 0U).i64();
5407
5408 BASIC_BLOCK(2U, -1L)
5409 {
5410 INST(2U, Opcode::Cast).b().SrcType(DataType::INT64).Inputs(0U);
5411 INST(3U, Opcode::Return).b().Inputs(2U);
5412 }
5413 }
5414 ASSERT_TRUE(graph->RunPass<Peepholes>());
5415 graph->RunPass<Cleanup>();
5416 ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5417 }
5418
TEST_F(PeepholesTest,CastI64ToBSignMismatch)5419 TEST_F(PeepholesTest, CastI64ToBSignMismatch)
5420 {
5421 auto graph = CreateEmptyGraph();
5422 GRAPH(graph)
5423 {
5424 PARAMETER(0U, 0U).i64();
5425
5426 BASIC_BLOCK(2U, -1L)
5427 {
5428 INST(1U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(0U);
5429 INST(2U, Opcode::Cast).b().SrcType(DataType::UINT32).Inputs(1U);
5430 INST(3U, Opcode::Return).b().Inputs(2U);
5431 }
5432 }
5433
5434 #ifndef NDEBUG
5435 ASSERT_DEATH(graph->RunPass<Peepholes>(), "");
5436 #else
5437 ASSERT_FALSE(graph->RunPass<Peepholes>());
5438 #endif
5439 }
5440
TEST_F(PeepholesTest,CastI64ToBTypeMismatch)5441 TEST_F(PeepholesTest, CastI64ToBTypeMismatch)
5442 {
5443 auto graph = CreateEmptyGraph();
5444 GRAPH(graph)
5445 {
5446 PARAMETER(0U, 0U).i64();
5447
5448 BASIC_BLOCK(2U, -1L)
5449 {
5450 INST(1U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(0U);
5451 INST(2U, Opcode::Cast).b().SrcType(DataType::INT16).Inputs(1U);
5452 INST(3U, Opcode::Return).b().Inputs(2U);
5453 }
5454 }
5455
5456 #ifndef NDEBUG
5457 ASSERT_DEATH(graph->RunPass<Peepholes>(), "");
5458 #else
5459 ASSERT_FALSE(graph->RunPass<Peepholes>());
5460 #endif
5461 }
5462
TEST_F(PeepholesTest,ConstCombineAdd)5463 TEST_F(PeepholesTest, ConstCombineAdd)
5464 {
5465 auto graph1 = CreateEmptyGraph();
5466 GRAPH(graph1)
5467 {
5468 PARAMETER(0U, 0U).i64();
5469 CONSTANT(1U, 3U);
5470 CONSTANT(2U, 7U);
5471 BASIC_BLOCK(2U, 1U)
5472 {
5473 INST(3U, Opcode::Add).s64().Inputs(0U, 1U);
5474 INST(4U, Opcode::Add).s64().Inputs(3U, 2U);
5475 INST(5U, Opcode::Return).s64().Inputs(4U);
5476 }
5477 }
5478 auto graph2 = CreateEmptyGraph();
5479 GRAPH(graph2)
5480 {
5481 PARAMETER(0U, 0U).i64();
5482 CONSTANT(6U, 10U);
5483 BASIC_BLOCK(2U, 1U)
5484 {
5485 INST(4U, Opcode::Add).s64().Inputs(0U, 6U);
5486 INST(5U, Opcode::Return).s64().Inputs(4U);
5487 }
5488 }
5489 ASSERT_TRUE(graph1->RunPass<Peepholes>());
5490 graph1->RunPass<Cleanup>();
5491 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5492 }
5493
TEST_F(PeepholesTest,ConstCombineAddSub)5494 TEST_F(PeepholesTest, ConstCombineAddSub)
5495 {
5496 auto graph1 = CreateEmptyGraph();
5497 GRAPH(graph1)
5498 {
5499 PARAMETER(0U, 0U).i64();
5500 CONSTANT(1U, 3U);
5501 CONSTANT(2U, 7U);
5502 BASIC_BLOCK(2U, 1U)
5503 {
5504 INST(3U, Opcode::Sub).s64().Inputs(0U, 1U);
5505 INST(4U, Opcode::Add).s64().Inputs(3U, 2U);
5506 INST(5U, Opcode::Return).s64().Inputs(4U);
5507 }
5508 }
5509 auto graph2 = CreateEmptyGraph();
5510 GRAPH(graph2)
5511 {
5512 PARAMETER(0U, 0U).i64();
5513 CONSTANT(6U, 4U);
5514 BASIC_BLOCK(2U, 1U)
5515 {
5516 INST(4U, Opcode::Add).s64().Inputs(0U, 6U);
5517 INST(5U, Opcode::Return).s64().Inputs(4U);
5518 }
5519 }
5520 ASSERT_TRUE(graph1->RunPass<Peepholes>());
5521 graph1->RunPass<Cleanup>();
5522 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5523 }
5524
TEST_F(PeepholesTest,ConstCombineSubAdd)5525 TEST_F(PeepholesTest, ConstCombineSubAdd)
5526 {
5527 auto graph1 = CreateEmptyGraph();
5528 GRAPH(graph1)
5529 {
5530 PARAMETER(0U, 0U).i64();
5531 CONSTANT(1U, 3U);
5532 CONSTANT(2U, 7U);
5533 BASIC_BLOCK(2U, 1U)
5534 {
5535 INST(3U, Opcode::Add).s64().Inputs(0U, 1U);
5536 INST(4U, Opcode::Sub).s64().Inputs(3U, 2U);
5537 INST(5U, Opcode::Return).s64().Inputs(4U);
5538 }
5539 }
5540 auto graph2 = CreateEmptyGraph();
5541 GRAPH(graph2)
5542 {
5543 PARAMETER(0U, 0U).i64();
5544 CONSTANT(6U, 4U);
5545 BASIC_BLOCK(2U, 1U)
5546 {
5547 INST(4U, Opcode::Sub).s64().Inputs(0U, 6U);
5548 INST(5U, Opcode::Return).s64().Inputs(4U);
5549 }
5550 }
5551 ASSERT_TRUE(graph1->RunPass<Peepholes>());
5552 graph1->RunPass<Cleanup>();
5553 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5554 }
5555
TEST_F(PeepholesTest,ConstCombineShift)5556 TEST_F(PeepholesTest, ConstCombineShift)
5557 {
5558 for (auto opcode : {Opcode::Shr, Opcode::Shl, Opcode::AShr}) {
5559 for (auto shift : {7U, 71U}) {
5560 auto graph1 = CreateEmptyGraph();
5561 GRAPH(graph1)
5562 {
5563 PARAMETER(0U, 0U).i64();
5564 CONSTANT(1U, 3U);
5565 CONSTANT(2U, shift);
5566 BASIC_BLOCK(2U, 1U)
5567 {
5568 INST(3U, opcode).s64().Inputs(0U, 1U);
5569 INST(4U, opcode).s64().Inputs(3U, 2U);
5570 INST(5U, Opcode::Return).s64().Inputs(4U);
5571 }
5572 }
5573 auto graph2 = CreateEmptyGraph();
5574 GRAPH(graph2)
5575 {
5576 PARAMETER(0U, 0U).i64();
5577 CONSTANT(6U, 10U);
5578 BASIC_BLOCK(2U, 1U)
5579 {
5580 INST(4U, opcode).s64().Inputs(0U, 6U);
5581 INST(5U, Opcode::Return).s64().Inputs(4U);
5582 }
5583 }
5584 ASSERT_TRUE(graph1->RunPass<Peepholes>());
5585 graph1->RunPass<Cleanup>();
5586 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5587 }
5588 }
5589 }
5590
TEST_F(PeepholesTest,ConstCombineShiftAlwaysZero)5591 TEST_F(PeepholesTest, ConstCombineShiftAlwaysZero)
5592 {
5593 for (auto opcode : {Opcode::Shr, Opcode::Shl}) {
5594 auto graph1 = CreateEmptyGraph();
5595 GRAPH(graph1)
5596 {
5597 PARAMETER(0U, 0U).i64();
5598 CONSTANT(1U, 31U);
5599 CONSTANT(2U, 33U);
5600 BASIC_BLOCK(2U, 1U)
5601 {
5602 INST(3U, opcode).s64().Inputs(0U, 1U);
5603 INST(4U, opcode).s64().Inputs(3U, 2U);
5604 INST(5U, Opcode::Return).s64().Inputs(4U);
5605 }
5606 }
5607 auto graph2 = CreateEmptyGraph();
5608 GRAPH(graph2)
5609 {
5610 CONSTANT(6U, 0U);
5611 BASIC_BLOCK(2U, 1U)
5612 {
5613 INST(5U, Opcode::Return).s64().Inputs(6U);
5614 }
5615 }
5616 ASSERT_TRUE(graph1->RunPass<Peepholes>());
5617 graph1->RunPass<Cleanup>();
5618 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5619 }
5620 }
5621
TEST_F(PeepholesTest,ConstCombineAShrMax)5622 TEST_F(PeepholesTest, ConstCombineAShrMax)
5623 {
5624 auto graph1 = CreateEmptyGraph();
5625 GRAPH(graph1)
5626 {
5627 PARAMETER(0U, 0U).i64();
5628 CONSTANT(1U, 31U);
5629 CONSTANT(2U, 33U);
5630 BASIC_BLOCK(2U, 1U)
5631 {
5632 INST(3U, Opcode::AShr).s64().Inputs(0U, 1U);
5633 INST(4U, Opcode::AShr).s64().Inputs(3U, 2U);
5634 INST(5U, Opcode::Return).s64().Inputs(4U);
5635 }
5636 }
5637 auto graph2 = CreateEmptyGraph();
5638 GRAPH(graph2)
5639 {
5640 PARAMETER(0U, 0U).i64();
5641 CONSTANT(6U, 63U);
5642 BASIC_BLOCK(2U, 1U)
5643 {
5644 INST(4U, Opcode::AShr).s64().Inputs(0U, 6U);
5645 INST(5U, Opcode::Return).s64().Inputs(4U);
5646 }
5647 }
5648 ASSERT_TRUE(graph1->RunPass<Peepholes>());
5649 graph1->RunPass<Cleanup>();
5650 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5651 }
5652
TEST_F(PeepholesTest,ConstCombineMul)5653 TEST_F(PeepholesTest, ConstCombineMul)
5654 {
5655 auto graph1 = CreateEmptyGraph();
5656 GRAPH(graph1)
5657 {
5658 PARAMETER(0U, 0U).i64();
5659 CONSTANT(1U, 3U);
5660 CONSTANT(2U, 7U);
5661 BASIC_BLOCK(2U, 1U)
5662 {
5663 INST(3U, Opcode::Mul).s64().Inputs(0U, 1U);
5664 INST(4U, Opcode::Mul).s64().Inputs(3U, 2U);
5665 INST(5U, Opcode::Return).s64().Inputs(4U);
5666 }
5667 }
5668 auto graph2 = CreateEmptyGraph();
5669 GRAPH(graph2)
5670 {
5671 PARAMETER(0U, 0U).i64();
5672 CONSTANT(6U, 21U);
5673 BASIC_BLOCK(2U, 1U)
5674 {
5675 INST(4U, Opcode::Mul).s64().Inputs(0U, 6U);
5676 INST(5U, Opcode::Return).s64().Inputs(4U);
5677 }
5678 }
5679 ASSERT_TRUE(graph1->RunPass<Peepholes>());
5680 graph1->RunPass<Cleanup>();
5681 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5682 }
5683
SRC_GRAPH(ConditionalAssignment,Graph * graph,bool inverse)5684 SRC_GRAPH(ConditionalAssignment, Graph *graph, bool inverse)
5685 {
5686 GRAPH(graph)
5687 {
5688 PARAMETER(0U, 0U).b();
5689 CONSTANT(2U, 0x0U).s64();
5690 CONSTANT(4U, 0x1U).s32();
5691 CONSTANT(5U, 0x0U).s32();
5692
5693 BASIC_BLOCK(2U, 3U, 4U)
5694 {
5695 INST(1U, Opcode::Compare).b().SrcType(DataType::BOOL).CC(CC_NE).Inputs(0U, 2U);
5696 INST(3U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(inverse ? CC_NE : CC_EQ).Imm(0U).Inputs(1U);
5697 }
5698
5699 BASIC_BLOCK(4U, 3U) {}
5700
5701 BASIC_BLOCK(3U, -1L)
5702 {
5703 INST(6U, Opcode::Phi).b().Inputs(5U, 4U);
5704 INST(7U, Opcode::Return).b().Inputs(6U);
5705 }
5706 }
5707 }
5708
OUT_GRAPH(ConditionalAssignment,Graph * graph)5709 OUT_GRAPH(ConditionalAssignment, Graph *graph)
5710 {
5711 GRAPH(graph)
5712 {
5713 PARAMETER(0U, 0U).b();
5714
5715 BASIC_BLOCK(2U, -1L)
5716 {
5717 INST(7U, Opcode::Return).b().Inputs(0U);
5718 }
5719 }
5720 }
5721
OUT_GRAPH(ConditionalAssignmentInverse,Graph * graph)5722 OUT_GRAPH(ConditionalAssignmentInverse, Graph *graph)
5723 {
5724 GRAPH(graph)
5725 {
5726 PARAMETER(0U, 0U).b();
5727
5728 BASIC_BLOCK(2U, -1L)
5729 {
5730 INST(10U, Opcode::XorI).b().Inputs(0U).Imm(1U);
5731 INST(7U, Opcode::Return).b().Inputs(10U);
5732 }
5733 }
5734 }
5735
TEST_F(PeepholesTest,ConditionalAssignment)5736 TEST_F(PeepholesTest, ConditionalAssignment)
5737 {
5738 for (auto inverse : {true, false}) {
5739 auto graph = CreateEmptyBytecodeGraph();
5740 src_graph::ConditionalAssignment::CREATE(graph, inverse);
5741
5742 #ifndef NDEBUG
5743 graph->SetLowLevelInstructionsEnabled();
5744 #endif
5745
5746 EXPECT_TRUE(graph->RunPass<Peepholes>());
5747 EXPECT_TRUE(graph->RunPass<Cleanup>());
5748 EXPECT_TRUE(graph->RunPass<Lowering>());
5749 graph->RunPass<Cleanup>();
5750
5751 auto expected = CreateEmptyBytecodeGraph();
5752 if (inverse) {
5753 out_graph::ConditionalAssignmentInverse::CREATE(expected);
5754 } else {
5755 out_graph::ConditionalAssignment::CREATE(expected);
5756 }
5757 EXPECT_TRUE(GraphComparator().Compare(graph, expected));
5758 }
5759 }
5760
SRC_GRAPH(ConditionalAssignmentPreserveIf,Graph * graph,bool inverse)5761 SRC_GRAPH(ConditionalAssignmentPreserveIf, Graph *graph, bool inverse)
5762 {
5763 GRAPH(graph)
5764 {
5765 PARAMETER(0U, 0U).u64();
5766 CONSTANT(4U, 1U);
5767 CONSTANT(5U, 0U);
5768
5769 BASIC_BLOCK(2U, 3U, 4U)
5770 {
5771 INST(1U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_GT).Inputs(0U, 4U);
5772 INST(3U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(inverse ? CC_NE : CC_EQ).Imm(0U).Inputs(1U);
5773 }
5774
5775 BASIC_BLOCK(4U, 3U)
5776 {
5777 INST(8U, Opcode::SaveState).NoVregs();
5778 INST(9U, Opcode::CallStatic).u64().InputsAutoType(8U);
5779 }
5780
5781 BASIC_BLOCK(3U, -1L)
5782 {
5783 INST(6U, Opcode::Phi).b().Inputs(5U, 4U);
5784 INST(7U, Opcode::Return).b().Inputs(6U);
5785 }
5786 }
5787 }
5788
OUT_GRAPH(ConditionalAssignmentPreserveIf,Graph * expected,bool inverse)5789 OUT_GRAPH(ConditionalAssignmentPreserveIf, Graph *expected, bool inverse)
5790 {
5791 GRAPH(expected)
5792 {
5793 PARAMETER(0U, 0U).u64();
5794 CONSTANT(4U, 1U);
5795 if (inverse) {
5796 CONSTANT(5U, 0U);
5797 }
5798
5799 BASIC_BLOCK(2U, 3U, 4U)
5800 {
5801 INST(1U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_GT).Inputs(0U, 4U);
5802 INST(3U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(inverse ? CC_NE : CC_EQ).Imm(0U).Inputs(1U);
5803 }
5804
5805 BASIC_BLOCK(4U, 3U)
5806 {
5807 INST(8U, Opcode::SaveState).NoVregs();
5808 INST(9U, Opcode::CallStatic).u64().InputsAutoType(8U);
5809 }
5810
5811 BASIC_BLOCK(3U, -1L)
5812 {
5813 if (inverse) {
5814 INST(11U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).SetType(DataType::BOOL).Inputs(1U, 5U);
5815 INST(7U, Opcode::Return).b().Inputs(11U);
5816 } else {
5817 INST(7U, Opcode::Return).b().Inputs(1U);
5818 }
5819 }
5820 }
5821 }
5822
TEST_F(PeepholesTest,ConditionalAssignmentPreserveIf)5823 TEST_F(PeepholesTest, ConditionalAssignmentPreserveIf)
5824 {
5825 for (auto inverse : {true, false}) {
5826 auto graph = CreateEmptyGraph();
5827 src_graph::ConditionalAssignmentPreserveIf::CREATE(graph, inverse);
5828
5829 ASSERT_TRUE(graph->RunPass<Peepholes>());
5830 ASSERT_TRUE(graph->RunPass<Cleanup>());
5831
5832 auto expected = CreateEmptyGraph();
5833 out_graph::ConditionalAssignmentPreserveIf::CREATE(expected, inverse);
5834
5835 EXPECT_TRUE(GraphComparator().Compare(graph, expected));
5836 }
5837 }
5838
TEST_F(PeepholesTest,ConditionalAssignmentBytecodeCompare)5839 TEST_F(PeepholesTest, ConditionalAssignmentBytecodeCompare)
5840 {
5841 // In case of bytecode optimizer we can not generate Compare instruction,
5842 // the optimization isn't applied
5843 auto graph = CreateEmptyBytecodeGraph();
5844 GRAPH(graph)
5845 {
5846 PARAMETER(0U, 0U).s32();
5847 CONSTANT(1U, 0x0U).s32();
5848 CONSTANT(2U, 0x1U).s32();
5849
5850 BASIC_BLOCK(2U, 3U, 4U)
5851 {
5852 INST(3U, Opcode::Compare).b().SrcType(DataType::INT32).CC(CC_GT).Inputs(0U, 2U);
5853 INST(4U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
5854 }
5855
5856 BASIC_BLOCK(4U, 3U) {}
5857
5858 BASIC_BLOCK(3U, -1L)
5859 {
5860 INST(5U, Opcode::Phi).b().Inputs(1U, 2U);
5861 INST(6U, Opcode::Return).b().Inputs(5U);
5862 }
5863 }
5864
5865 ASSERT_FALSE(graph->RunPass<Peepholes>());
5866 }
5867
TEST_F(PeepholesTest,ConditionalAssignmentWrongConstants)5868 TEST_F(PeepholesTest, ConditionalAssignmentWrongConstants)
5869 {
5870 // Constants are the same or not equal to 0 and 1
5871 for (auto constant : {0U, 2U}) {
5872 auto graph = CreateEmptyGraph();
5873 GRAPH(graph)
5874 {
5875 PARAMETER(0U, 0U).s32();
5876 CONSTANT(1U, 0U).s32();
5877 CONSTANT(2U, constant).s32();
5878
5879 BASIC_BLOCK(2U, 3U, 4U)
5880 {
5881 INST(3U, Opcode::Compare).b().SrcType(DataType::INT32).CC(CC_GT).Inputs(0U, 2U);
5882 INST(4U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
5883 }
5884
5885 BASIC_BLOCK(4U, 3U) {}
5886
5887 BASIC_BLOCK(3U, -1L)
5888 {
5889 INST(5U, Opcode::Phi).b().Inputs(1U, 2U);
5890 INST(6U, Opcode::Return).b().Inputs(5U);
5891 }
5892 }
5893
5894 EXPECT_FALSE(graph->RunPass<Peepholes>());
5895 }
5896 }
5897
SRC_GRAPH(ConditionalAssignmentsTwoBranches,Graph * graph,bool inverse)5898 SRC_GRAPH(ConditionalAssignmentsTwoBranches, Graph *graph, bool inverse)
5899 {
5900 GRAPH(graph)
5901 {
5902 PARAMETER(0U, 0U).b();
5903 CONSTANT(2U, 0x0U).s64();
5904 CONSTANT(4U, 0x1U).s32();
5905 CONSTANT(5U, 0x0U).s32();
5906
5907 BASIC_BLOCK(2U, 4U, 5U)
5908 {
5909 INST(1U, Opcode::Compare).b().SrcType(DataType::BOOL).CC(CC_NE).Inputs(0U, 2U);
5910 INST(3U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(inverse ? CC_NE : CC_EQ).Imm(0U).Inputs(1U);
5911 }
5912
5913 BASIC_BLOCK(4U, 6U) {}
5914 BASIC_BLOCK(6U, 3U) {}
5915
5916 BASIC_BLOCK(5U, 3U) {}
5917
5918 BASIC_BLOCK(3U, -1L)
5919 {
5920 INST(6U, Opcode::Phi).b().Inputs(4U, 5U);
5921 INST(7U, Opcode::Return).b().Inputs(6U);
5922 }
5923 }
5924 }
5925
TEST_F(PeepholesTest,ConditionalAssignmentsTwoBranches)5926 TEST_F(PeepholesTest, ConditionalAssignmentsTwoBranches)
5927 {
5928 for (auto inverse : {true, false}) {
5929 auto graph = CreateEmptyBytecodeGraph();
5930 src_graph::ConditionalAssignmentsTwoBranches::CREATE(graph, inverse);
5931
5932 #ifndef NDEBUG
5933 graph->SetLowLevelInstructionsEnabled();
5934 #endif
5935
5936 EXPECT_TRUE(graph->RunPass<Peepholes>());
5937 EXPECT_TRUE(graph->RunPass<Cleanup>());
5938 EXPECT_TRUE(graph->RunPass<Lowering>());
5939 graph->RunPass<Cleanup>();
5940
5941 auto expected = CreateEmptyBytecodeGraph();
5942 if (!inverse) {
5943 GRAPH(expected)
5944 {
5945 PARAMETER(0U, 0U).b();
5946
5947 BASIC_BLOCK(2U, -1L)
5948 {
5949 INST(10U, Opcode::XorI).b().Inputs(0U).Imm(1U);
5950 INST(7U, Opcode::Return).b().Inputs(10U);
5951 }
5952 }
5953 } else {
5954 GRAPH(expected)
5955 {
5956 PARAMETER(0U, 0U).b();
5957
5958 BASIC_BLOCK(2U, -1L)
5959 {
5960 INST(7U, Opcode::Return).b().Inputs(0U);
5961 }
5962 }
5963 }
5964 EXPECT_TRUE(GraphComparator().Compare(graph, expected));
5965 }
5966 }
5967
5968 /* We cannot replace Phi because its value may come from both branches of If
5969 * [entry]
5970 * |
5971 * v
5972 * [2]--->[4]
5973 * | |
5974 * v v
5975 * [3]--->[5]
5976 * | |
5977 * v |
5978 * [6]<----/
5979 * |
5980 * v
5981 * [exit]
5982 */
TEST_F(PeepholesTest,ConditionalAssignmentMixedBranches)5983 TEST_F(PeepholesTest, ConditionalAssignmentMixedBranches)
5984 {
5985 GRAPH(GetGraph())
5986 {
5987 PARAMETER(0U, 0U).u64();
5988 CONSTANT(1U, 0U);
5989 CONSTANT(2U, 1U);
5990
5991 BASIC_BLOCK(2U, 3U, 4U)
5992 {
5993 INST(4U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_NE).Inputs(0U, 1U);
5994 INST(5U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
5995 }
5996
5997 BASIC_BLOCK(3U, 5U, 6U)
5998 {
5999 INST(6U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_NE).Inputs(0U, 2U);
6000 INST(7U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(1U);
6001 }
6002
6003 BASIC_BLOCK(4U, 5U) {}
6004
6005 BASIC_BLOCK(5U, 6U) {}
6006
6007 BASIC_BLOCK(6U, -1L)
6008 {
6009 INST(8U, Opcode::Phi).b().Inputs(1U, 2U);
6010 INST(9U, Opcode::Return).b().Inputs(8U);
6011 }
6012 }
6013 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
6014 }
6015
6016 /* We can go to true branch, to block 5, to block 4, and to block 5 again
6017 * So we need to check that block 3 has one predecessor
6018 * [entry]
6019 * |
6020 * v F
6021 * [2]-->[3]<--\
6022 * T | | |
6023 * | v |
6024 * \--->[4]---/
6025 * |
6026 * v
6027 * [5]
6028 * |
6029 * v
6030 * [exit]
6031 */
TEST_F(PeepholesTest,ConditionalAssignmentLoopTriangle)6032 TEST_F(PeepholesTest, ConditionalAssignmentLoopTriangle)
6033 {
6034 for (auto inverse : {true, false}) {
6035 auto graph = CreateEmptyGraph();
6036 GRAPH(graph)
6037 {
6038 PARAMETER(0U, 0U).u64();
6039 PARAMETER(1U, 1U).u64();
6040 CONSTANT(2U, 0U);
6041 CONSTANT(3U, 1U);
6042
6043 BASIC_BLOCK(2U, 4U, 3U)
6044 {
6045 INST(4U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_NE).Inputs(0U, 2U);
6046 INST(5U, Opcode::IfImm)
6047 .SrcType(compiler::DataType::BOOL)
6048 .CC(inverse ? CC_EQ : CC_NE)
6049 .Imm(0U)
6050 .Inputs(4U);
6051 }
6052
6053 BASIC_BLOCK(3U, 4U) {}
6054
6055 BASIC_BLOCK(4U, 5U, 3U)
6056 {
6057 INST(6U, Opcode::Phi).b().Inputs(2U, 3U);
6058 INST(7U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_LT).Inputs(1U, 3U);
6059 INST(8U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
6060 }
6061
6062 BASIC_BLOCK(5U, -1L)
6063 {
6064 INST(9U, Opcode::Return).b().Inputs(6U);
6065 }
6066 }
6067 EXPECT_FALSE(graph->RunPass<Peepholes>());
6068 }
6069 }
6070
6071 /* We can go to true branch, to block 5, to block 4, and to block 5 again
6072 * So we need to check that block 3 has one predecessor
6073 *
6074 * [entry]
6075 * |
6076 * v F
6077 * [2]-->[3]<--\
6078 * T | | |
6079 * v v |
6080 * [4]-->[5]---/
6081 * |
6082 * v
6083 * [6]
6084 * |
6085 * v
6086 * [exit]
6087 */
TEST_F(PeepholesTest,ConditionalAssignmentLoopDiamond)6088 TEST_F(PeepholesTest, ConditionalAssignmentLoopDiamond)
6089 {
6090 for (auto inverse : {true, false}) {
6091 auto graph = CreateEmptyGraph();
6092 GRAPH(graph)
6093 {
6094 PARAMETER(0U, 0U).u64();
6095 PARAMETER(1U, 1U).u64();
6096 CONSTANT(2U, 0U);
6097 CONSTANT(3U, 1U);
6098
6099 BASIC_BLOCK(2U, 4U, 3U)
6100 {
6101 INST(4U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_NE).Inputs(0U, 2U);
6102 INST(5U, Opcode::IfImm)
6103 .SrcType(compiler::DataType::BOOL)
6104 .CC(inverse ? CC_EQ : CC_NE)
6105 .Imm(0U)
6106 .Inputs(4U);
6107 }
6108
6109 BASIC_BLOCK(3U, 5U) {}
6110
6111 BASIC_BLOCK(4U, 5U)
6112 {
6113 INST(6U, Opcode::SaveState).NoVregs();
6114 INST(7U, Opcode::CallStatic).u64().InputsAutoType(0U, 6U);
6115 }
6116
6117 BASIC_BLOCK(5U, 6U, 3U)
6118 {
6119 INST(8U, Opcode::Phi).b().Inputs(2U, 3U);
6120 INST(9U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_LT).Inputs(1U, 3U);
6121 INST(10U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
6122 }
6123
6124 BASIC_BLOCK(6U, -1L)
6125 {
6126 INST(11U, Opcode::Return).b().Inputs(8U);
6127 }
6128 }
6129 EXPECT_FALSE(graph->RunPass<Peepholes>());
6130 }
6131 }
6132
6133 /*
6134 * [entry]
6135 * |
6136 * v
6137 * [2]------\
6138 * | |
6139 * | v
6140 * | /---[3]---\
6141 * | | |
6142 * | v v
6143 * | [4] [5]
6144 * | | |
6145 * | \-->[6]<--/
6146 * | |
6147 * v |
6148 * [7]<-----/
6149 * |
6150 * v
6151 * [exit]
6152 */
TEST_F(PeepholesTest,ConditionalAssignmentNestedIfs)6153 TEST_F(PeepholesTest, ConditionalAssignmentNestedIfs)
6154 {
6155 GRAPH(GetGraph())
6156 {
6157 PARAMETER(0U, 0U).s64();
6158 CONSTANT(1U, 0U);
6159 CONSTANT(2U, 1U);
6160
6161 BASIC_BLOCK(2U, 7U, 3U)
6162 {
6163 INST(3U, Opcode::Compare).b().SrcType(DataType::INT64).CC(CC_LT).Inputs(0U, 1U);
6164 INST(4U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
6165 }
6166
6167 BASIC_BLOCK(3U, 4U, 5U)
6168 {
6169 INST(5U, Opcode::Compare).b().SrcType(DataType::INT64).CC(CC_GT).Inputs(0U, 2U);
6170 INST(6U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
6171 }
6172
6173 BASIC_BLOCK(4U, 6U)
6174 {
6175 INST(7U, Opcode::Add).s64().Inputs(0U, 2U);
6176 }
6177 BASIC_BLOCK(5U, 6U)
6178 {
6179 INST(8U, Opcode::Sub).s64().Inputs(0U, 2U);
6180 }
6181
6182 BASIC_BLOCK(6U, 7U)
6183 {
6184 INST(9U, Opcode::Phi).s64().Inputs(7U, 8U);
6185 }
6186
6187 BASIC_BLOCK(7U, -1L)
6188 {
6189 INST(10U, Opcode::Phi).b().Inputs(2U, 1U);
6190 INST(11U, Opcode::Phi).s64().Inputs(0U, 9U);
6191 INST(12U, Opcode::SaveState).NoVregs();
6192 INST(13U, Opcode::CallStatic).u64().InputsAutoType(10U, 11U, 12U);
6193 INST(14U, Opcode::Return).u64().Inputs(13U);
6194 }
6195 }
6196
6197 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6198
6199 ASSERT_EQ(INS(13U).GetInput(0U).GetInst(), &INS(3U));
6200 }
6201
TEST_F(PeepholesTest,OverflowChecksOptimize)6202 TEST_F(PeepholesTest, OverflowChecksOptimize)
6203 {
6204 GRAPH(GetGraph())
6205 {
6206 CONSTANT(0U, 0U);
6207 PARAMETER(1U, 0U).s32();
6208 BASIC_BLOCK(2U, -1L)
6209 {
6210 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6211 INST(3U, Opcode::AddOverflowCheck).s32().Inputs(1U, 0U, 2U);
6212 INST(4U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);
6213 INST(5U, Opcode::SubOverflowCheck).s32().Inputs(1U, 0U, 2U);
6214 INST(6U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 2U); // can't optimize (0 - x)
6215 INST(7U, Opcode::CallStatic).v0id().InputsAutoType(3U, 4U, 5U, 6U, 2U);
6216 INST(8U, Opcode::ReturnVoid).v0id();
6217 }
6218 }
6219 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6220 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
6221 auto graph = CreateEmptyGraph();
6222 GRAPH(graph)
6223 {
6224 CONSTANT(0U, 0U);
6225 PARAMETER(1U, 0U).s32();
6226 BASIC_BLOCK(2U, -1L)
6227 {
6228 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6229 INST(6U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 2U); // can't optimize (0 - x)
6230 INST(7U, Opcode::CallStatic).v0id().InputsAutoType(1U, 1U, 1U, 6U, 2U);
6231 INST(8U, Opcode::ReturnVoid).v0id();
6232 }
6233 }
6234 ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
6235 }
6236
6237 /* We check, that in Peephole if new inputs (which is not Constant) and inst in different BB in OSR mode,
6238 * optimization will not apply.
6239 *
6240 * What check:
6241 * 0.u64 Param
6242 * 1.u64 Param
6243 * 14.u64 Param
6244 * ...
6245 * BB 2
6246 * 15.u64 Add v1, v0
6247 * 16.u64 Add v0, v14
6248 * ...
6249 * BB 3
6250 * 17.u64 Sub v15, v16 <<== Inputs will NOT change
6251 */
TEST_F(PeepholesTest,SubAddAddFromOtherBBInOsrMode)6252 TEST_F(PeepholesTest, SubAddAddFromOtherBBInOsrMode)
6253 {
6254 auto graphOsr = CreateEmptyGraph();
6255 graphOsr->SetMode(GraphMode::Osr());
6256
6257 GRAPH(graphOsr)
6258 {
6259 PARAMETER(0U, 0U).u64();
6260 PARAMETER(1U, 1U).u64();
6261 PARAMETER(14U, 2U).u64();
6262 BASIC_BLOCK(2U, 3U, 4U)
6263 {
6264 INST(15U, Opcode::Add).u64().Inputs(1U, 0U);
6265 INST(16U, Opcode::Add).u64().Inputs(0U, 14U);
6266
6267 INST(2U, Opcode::Add).u64().Inputs(0U, 1U);
6268 INST(3U, Opcode::Compare).b().Inputs(0U, 2U);
6269 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
6270 }
6271 BASIC_BLOCK(3U, 3U, 4U)
6272 {
6273 INST(5U, Opcode::Phi).u64().Inputs({{2U, 0U}, {3U, 6U}});
6274 INST(13U, Opcode::SaveStateOsr).Inputs(0U, 1U, 5U, 15U, 16U).SrcVregs({0U, 1U, 2U, 3U, 4U});
6275 INST(6U, Opcode::Sub).u64().Inputs(5U, 1U);
6276 // This INST 17 will not change!
6277 INST(17U, Opcode::Sub).u64().Inputs(15U, 16U);
6278 INST(7U, Opcode::Compare).b().Inputs(6U, 1U);
6279 INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
6280 }
6281 BASIC_BLOCK(4U, -1L)
6282 {
6283 INST(9U, Opcode::Phi).u64().Inputs({{2U, 0U}, {3U, 6U}});
6284 INST(10U, Opcode::Add).u64().Inputs(0U, 1U);
6285 INST(11U, Opcode::Add).u64().Inputs(9U, 10U);
6286 INST(12U, Opcode::Return).u64().Inputs(11U);
6287 }
6288 }
6289
6290 for (auto bb : graphOsr->GetBlocksRPO()) {
6291 if (bb->IsLoopHeader()) {
6292 bb->SetOsrEntry(true);
6293 }
6294 }
6295 auto cloneOsr = GraphCloner(graphOsr, graphOsr->GetAllocator(), graphOsr->GetLocalAllocator()).CloneGraph();
6296 cloneOsr->RunPass<Peepholes>();
6297 ASSERT_TRUE(GraphComparator().Compare(graphOsr, cloneOsr));
6298 }
6299
6300 /* We check, that if in Peephole new inputs and inst in different BB in OSR mode for Constants,
6301 * optimization will apply.
6302 *
6303 * What check:
6304 * 14. Const -> v15
6305 * 19. Const -> v16
6306 * ...
6307 * BB 2
6308 * 15.u64 Add v14, v1 -> v17
6309 * 16.u64 Add v1, v19 -> v17
6310 * ...
6311 * BB 3
6312 * 17.u64 Sub v15, v16 <<== Inputs will change
6313 * ============>
6314 * 14. Const -> v15, v17
6315 * 19. Const -> v16, v17
6316 * ...
6317 * BB 2
6318 * 15.u64 Add v14, v1
6319 * 16.u64 Add v1, v19
6320 * ...
6321 * BB 3
6322 * 17.u64 Sub v14, v19 <<== Inputs changed
6323 */
TEST_F(PeepholesTest,SubAddAddSameBBInOsrMode)6324 TEST_F(PeepholesTest, SubAddAddSameBBInOsrMode)
6325 {
6326 GetGraph()->SetMode(GraphMode::Osr());
6327 // (const0 + param) - (param + const1) = const0 - const1
6328 GRAPH(GetGraph())
6329 {
6330 PARAMETER(0U, 0U).u64();
6331 PARAMETER(1U, 1U).u64();
6332
6333 CONSTANT(14U, 0U);
6334 CONSTANT(19U, 2U);
6335
6336 BASIC_BLOCK(2U, 3U, 4U)
6337 {
6338 INST(2U, Opcode::Add).u64().Inputs(0U, 1U);
6339 INST(3U, Opcode::Compare).b().Inputs(0U, 2U);
6340 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
6341 }
6342 BASIC_BLOCK(3U, 3U, 4U)
6343 {
6344 INST(5U, Opcode::Phi).u64().Inputs({{2U, 0U}, {3U, 6U}});
6345 INST(13U, Opcode::SaveStateOsr).Inputs(0U, 1U, 5U).SrcVregs({0U, 1U, 2U});
6346 INST(6U, Opcode::Sub).u64().Inputs(5U, 1U);
6347
6348 INST(15U, Opcode::Add).u64().Inputs(14U, 1U);
6349 INST(16U, Opcode::Add).u64().Inputs(1U, 19U);
6350 // INST 17 will change
6351 INST(17U, Opcode::Sub).u64().Inputs(15U, 16U);
6352 INST(7U, Opcode::Compare).b().Inputs(6U, 1U);
6353 INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
6354 }
6355 BASIC_BLOCK(4U, -1L)
6356 {
6357 INST(9U, Opcode::Phi).u64().Inputs({{2U, 0U}, {3U, 6U}});
6358 INST(10U, Opcode::Add).u64().Inputs(0U, 1U);
6359 INST(11U, Opcode::Add).u64().Inputs(9U, 10U);
6360 INST(12U, Opcode::Return).u64().Inputs(11U);
6361 }
6362 }
6363
6364 for (auto bb : GetGraph()->GetBlocksRPO()) {
6365 if (bb->IsLoopHeader()) {
6366 bb->SetOsrEntry(true);
6367 }
6368 }
6369 GetGraph()->RunPass<Peepholes>();
6370 GraphChecker(GetGraph()).Check();
6371 ASSERT_EQ(INS(17U).GetInput(0U).GetInst(), &INS(14U));
6372 ASSERT_EQ(INS(17U).GetInput(1U).GetInst(), &INS(19U));
6373 }
6374
TEST_F(PeepholesTest,GetInstanceClassTest)6375 TEST_F(PeepholesTest, GetInstanceClassTest)
6376 {
6377 auto klass = reinterpret_cast<RuntimeInterface::ClassPtr>(2U);
6378 GRAPH(GetGraph())
6379 {
6380 BASIC_BLOCK(2U, -1L)
6381 {
6382 INST(0U, Opcode::SaveState).NoVregs();
6383 INST(1U, Opcode::LoadAndInitClass).ref().Inputs(0U).TypeId(1U).Class(klass);
6384 INST(2U, Opcode::NewObject).ref().Inputs(1U, 0U).TypeId(1U);
6385 INST(3U, Opcode::GetInstanceClass).ref().Inputs(2U);
6386 INST(4U, Opcode::Return).ref().Inputs(3U);
6387 }
6388 }
6389 GetGraph()->RunPass<ObjectTypePropagation>(); // set analysis valid
6390 INS(2U).SetObjectTypeInfo(ObjectTypeInfo(klass, true));
6391 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6392 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
6393 auto graph = CreateEmptyGraph();
6394 GRAPH(graph)
6395 {
6396 BASIC_BLOCK(2U, -1L)
6397 {
6398 INST(0U, Opcode::SaveState).NoVregs();
6399 INST(1U, Opcode::LoadAndInitClass).ref().Inputs(0U).TypeId(1U).Class(klass);
6400 INST(2U, Opcode::NewObject).ref().Inputs(1U, 0U).TypeId(1U);
6401 INST(3U, Opcode::LoadImmediate).ref().Class(klass);
6402 INST(4U, Opcode::Return).ref().Inputs(3U);
6403 }
6404 }
6405 ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
6406 }
6407
6408 // Replace by Neg
TEST_F(PeepholesTest,NegOverflowAndZeroCheckShl)6409 TEST_F(PeepholesTest, NegOverflowAndZeroCheckShl)
6410 {
6411 auto graph1 = CreateEmptyGraph();
6412 GRAPH(graph1)
6413 {
6414 PARAMETER(0U, 0U).s32();
6415 CONSTANT(1U, 1U);
6416 BASIC_BLOCK(2U, -1L)
6417 {
6418 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6419 INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6420 INST(7U, Opcode::Shl).s32().Inputs(6U, 1U);
6421 INST(8U, Opcode::Return).s32().Inputs(7U);
6422 }
6423 }
6424 ASSERT_TRUE(graph1->RunPass<Peepholes>());
6425 auto graph2 = CreateEmptyGraph();
6426 GRAPH(graph2)
6427 {
6428 PARAMETER(0U, 0U).s32();
6429 CONSTANT(1U, 1U);
6430 BASIC_BLOCK(2U, -1L)
6431 {
6432 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6433 INST(6U, Opcode::Neg).s32().Inputs(0U);
6434 INST(7U, Opcode::Shl).s32().Inputs(6U, 1U);
6435 INST(8U, Opcode::Return).s32().Inputs(7U);
6436 }
6437 }
6438 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6439 }
6440
TEST_F(PeepholesTest,NegOverflowAndZeroCheckShr)6441 TEST_F(PeepholesTest, NegOverflowAndZeroCheckShr)
6442 {
6443 auto graph1 = CreateEmptyGraph();
6444 GRAPH(graph1)
6445 {
6446 PARAMETER(0U, 0U).s32();
6447 CONSTANT(1U, 1U);
6448 BASIC_BLOCK(2U, -1L)
6449 {
6450 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6451 INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6452 INST(7U, Opcode::Shr).s32().Inputs(6U, 1U);
6453 INST(8U, Opcode::Return).s32().Inputs(7U);
6454 }
6455 }
6456 ASSERT_TRUE(graph1->RunPass<Peepholes>());
6457 auto graph2 = CreateEmptyGraph();
6458 GRAPH(graph2)
6459 {
6460 PARAMETER(0U, 0U).s32();
6461 CONSTANT(1U, 1U);
6462 BASIC_BLOCK(2U, -1L)
6463 {
6464 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6465 INST(6U, Opcode::Neg).s32().Inputs(0U);
6466 INST(7U, Opcode::Shr).s32().Inputs(6U, 1U);
6467 INST(8U, Opcode::Return).s32().Inputs(7U);
6468 }
6469 }
6470 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6471 }
6472
TEST_F(PeepholesTest,NegOverflowAndZeroCheckAShr)6473 TEST_F(PeepholesTest, NegOverflowAndZeroCheckAShr)
6474 {
6475 auto graph1 = CreateEmptyGraph();
6476 GRAPH(graph1)
6477 {
6478 PARAMETER(0U, 0U).s32();
6479 CONSTANT(1U, 1U);
6480 BASIC_BLOCK(2U, -1L)
6481 {
6482 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6483 INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6484 INST(7U, Opcode::AShr).s32().Inputs(6U, 1U);
6485 INST(8U, Opcode::Return).s32().Inputs(7U);
6486 }
6487 }
6488 ASSERT_TRUE(graph1->RunPass<Peepholes>());
6489 auto graph2 = CreateEmptyGraph();
6490 GRAPH(graph2)
6491 {
6492 PARAMETER(0U, 0U).s32();
6493 CONSTANT(1U, 1U);
6494 BASIC_BLOCK(2U, -1L)
6495 {
6496 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6497 INST(6U, Opcode::Neg).s32().Inputs(0U);
6498 INST(7U, Opcode::AShr).s32().Inputs(6U, 1U);
6499 INST(8U, Opcode::Return).s32().Inputs(7U);
6500 }
6501 }
6502 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6503 }
6504
TEST_F(PeepholesTest,NegOverflowAndZeroCheckAnd)6505 TEST_F(PeepholesTest, NegOverflowAndZeroCheckAnd)
6506 {
6507 auto graph1 = CreateEmptyGraph();
6508 GRAPH(graph1)
6509 {
6510 PARAMETER(0U, 0U).s32();
6511 CONSTANT(1U, 1U);
6512 BASIC_BLOCK(2U, -1L)
6513 {
6514 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6515 INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6516 INST(7U, Opcode::And).u32().Inputs(6U, 1U);
6517 INST(8U, Opcode::Return).u32().Inputs(7U);
6518 }
6519 }
6520 ASSERT_TRUE(graph1->RunPass<Peepholes>());
6521 auto graph2 = CreateEmptyGraph();
6522 GRAPH(graph2)
6523 {
6524 PARAMETER(0U, 0U).s32();
6525 CONSTANT(1U, 1U);
6526 BASIC_BLOCK(2U, -1L)
6527 {
6528 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6529 INST(6U, Opcode::Neg).s32().Inputs(0U);
6530 INST(7U, Opcode::And).u32().Inputs(6U, 1U);
6531 INST(8U, Opcode::Return).u32().Inputs(7U);
6532 }
6533 }
6534 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6535 }
6536
TEST_F(PeepholesTest,NegOverflowAndZeroCheckOr)6537 TEST_F(PeepholesTest, NegOverflowAndZeroCheckOr)
6538 {
6539 auto graph1 = CreateEmptyGraph();
6540 GRAPH(graph1)
6541 {
6542 PARAMETER(0U, 0U).s32();
6543 CONSTANT(1U, 1U);
6544 BASIC_BLOCK(2U, -1L)
6545 {
6546 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6547 INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6548 INST(7U, Opcode::Or).u32().Inputs(6U, 1U);
6549 INST(8U, Opcode::Return).u32().Inputs(7U);
6550 }
6551 }
6552 ASSERT_TRUE(graph1->RunPass<Peepholes>());
6553 auto graph2 = CreateEmptyGraph();
6554 GRAPH(graph2)
6555 {
6556 PARAMETER(0U, 0U).s32();
6557 CONSTANT(1U, 1U);
6558 BASIC_BLOCK(2U, -1L)
6559 {
6560 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6561 INST(6U, Opcode::Neg).s32().Inputs(0U);
6562 INST(7U, Opcode::Or).u32().Inputs(6U, 1U);
6563 INST(8U, Opcode::Return).u32().Inputs(7U);
6564 }
6565 }
6566 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6567 }
6568
TEST_F(PeepholesTest,NegOverflowAndZeroCheckXor)6569 TEST_F(PeepholesTest, NegOverflowAndZeroCheckXor)
6570 {
6571 auto graph1 = CreateEmptyGraph();
6572 GRAPH(graph1)
6573 {
6574 PARAMETER(0U, 0U).s32();
6575 CONSTANT(1U, 1U);
6576 BASIC_BLOCK(2U, -1L)
6577 {
6578 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6579 INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6580 INST(7U, Opcode::Xor).u32().Inputs(6U, 1U);
6581 INST(8U, Opcode::Return).u32().Inputs(7U);
6582 }
6583 }
6584 ASSERT_TRUE(graph1->RunPass<Peepholes>());
6585 auto graph2 = CreateEmptyGraph();
6586 GRAPH(graph2)
6587 {
6588 PARAMETER(0U, 0U).s32();
6589 CONSTANT(1U, 1U);
6590 BASIC_BLOCK(2U, -1L)
6591 {
6592 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6593 INST(6U, Opcode::Neg).s32().Inputs(0U);
6594 INST(7U, Opcode::Xor).u32().Inputs(6U, 1U);
6595 INST(8U, Opcode::Return).u32().Inputs(7U);
6596 }
6597 }
6598 ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6599 }
6600
TEST_F(PeepholesTest,NegOverflowAndZeroCheckNotApplied)6601 TEST_F(PeepholesTest, NegOverflowAndZeroCheckNotApplied)
6602 {
6603 GRAPH(GetGraph())
6604 {
6605 PARAMETER(0U, 0U).s32();
6606 CONSTANT(1U, 1U);
6607 BASIC_BLOCK(2U, -1L)
6608 {
6609 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6610 INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6611 INST(7U, Opcode::Add).s32().Inputs(6U, 1U);
6612 INST(8U, Opcode::Return).s32().Inputs(7U);
6613 }
6614 }
6615 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
6616 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
6617 GraphChecker(GetGraph()).Check();
6618 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
6619 }
6620
SRC_GRAPH(OverflowCheckAsBitwiseInput,Graph * graph)6621 SRC_GRAPH(OverflowCheckAsBitwiseInput, Graph *graph)
6622 {
6623 GRAPH(graph)
6624 {
6625 PARAMETER(0U, 0U).s32();
6626 PARAMETER(1U, 1U).s32();
6627 PARAMETER(2U, 2U).s32();
6628 CONSTANT(3U, 0U);
6629 BASIC_BLOCK(2U, 4U, 3U)
6630 {
6631 INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
6632 INST(5U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 4U);
6633
6634 INST(6U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
6635 INST(7U, Opcode::SubOverflowCheck).s32().Inputs(5U, 2U, 6U);
6636
6637 INST(8U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::Type::INT32).Inputs(2U, 0U);
6638 INST(9U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(compiler::CC_NE).Imm(0U).Inputs(8U);
6639 }
6640
6641 BASIC_BLOCK(4U, 3U)
6642 {
6643 INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 5U, 7U).SrcVregs({0U, 1U, 2U, 3U, 4U, 5U});
6644 INST(11U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(2U, 10U);
6645 }
6646
6647 BASIC_BLOCK(3U, -1L)
6648 {
6649 INST(12U, Opcode::Phi).s32().Inputs({{2U, 7U}, {4U, 11U}});
6650 INST(13U, Opcode::Or).s32().Inputs(12U, 3U);
6651 INST(14U, Opcode::Return).s32().Inputs(13U);
6652 }
6653 }
6654 }
6655
OUT_GRAPH(OverflowCheckAsBitwiseInput,Graph * graph)6656 OUT_GRAPH(OverflowCheckAsBitwiseInput, Graph *graph)
6657 {
6658 GRAPH(graph)
6659 {
6660 PARAMETER(0U, 0U).s32();
6661 PARAMETER(1U, 1U).s32();
6662 PARAMETER(2U, 2U).s32();
6663 CONSTANT(3U, 0U);
6664 BASIC_BLOCK(2U, 4U, 3U)
6665 {
6666 INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
6667 INST(5U, Opcode::Add).s32().Inputs(0U, 1U);
6668
6669 INST(6U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
6670 INST(7U, Opcode::Sub).s32().Inputs(5U, 2U);
6671
6672 INST(8U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::Type::INT32).Inputs(2U, 0U);
6673 INST(9U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(compiler::CC_NE).Imm(0U).Inputs(8U);
6674 }
6675
6676 BASIC_BLOCK(4U, 3U)
6677 {
6678 INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 5U, 7U).SrcVregs({0U, 1U, 2U, 3U, 4U, 5U});
6679 INST(11U, Opcode::Neg).s32().Inputs(2U);
6680 }
6681
6682 BASIC_BLOCK(3U, -1L)
6683 {
6684 INST(12U, Opcode::Phi).s32().Inputs({{2U, 7U}, {4U, 11U}});
6685 INST(13U, Opcode::Or).s32().Inputs(12U, 3U);
6686 INST(14U, Opcode::Return).s32().Inputs(12U);
6687 }
6688 }
6689 }
6690
TEST_F(PeepholesTest,OverflowCheckAsBitwiseInput)6691 TEST_F(PeepholesTest, OverflowCheckAsBitwiseInput)
6692 {
6693 src_graph::OverflowCheckAsBitwiseInput::CREATE(GetGraph());
6694 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6695 auto graph = CreateEmptyGraph();
6696 out_graph::OverflowCheckAsBitwiseInput::CREATE(graph);
6697 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6698 }
6699
TEST_F(PeepholesTest,OverflowCheckAsBitwiseAndSSInput)6700 TEST_F(PeepholesTest, OverflowCheckAsBitwiseAndSSInput)
6701 {
6702 GRAPH(GetGraph())
6703 {
6704 PARAMETER(0U, 0U).s32();
6705 CONSTANT(1U, 255U);
6706 BASIC_BLOCK(2U, -1L)
6707 {
6708 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6709 INST(3U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);
6710
6711 INST(6U, Opcode::And).s32().Inputs(3U, 1U);
6712 INST(7U, Opcode::SaveState).Inputs(0U, 1U, 3U, 6U).SrcVregs({0U, 1U, 2U, 3U});
6713 INST(8U, Opcode::AddOverflowCheck).s32().Inputs(6U, 1U, 7U);
6714 INST(9U, Opcode::Return).s32().Inputs(8U);
6715 }
6716 }
6717 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
6718 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
6719 GraphChecker(GetGraph()).Check();
6720 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
6721 }
6722
TEST_F(PeepholesTest,ReplacingXorWithCompare)6723 TEST_F(PeepholesTest, ReplacingXorWithCompare)
6724 {
6725 GRAPH(GetGraph())
6726 {
6727 CONSTANT(0U, 1U);
6728 BASIC_BLOCK(2U, -1L)
6729 {
6730 INST(1U, Opcode::SaveState).NoVregs();
6731 INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
6732 INST(3U, Opcode::Xor).s32().Inputs(0U, 2U);
6733 INST(9U, Opcode::Return).s32().Inputs(3U);
6734 }
6735 }
6736
6737 auto graph = CreateEmptyGraph();
6738 GRAPH(graph)
6739 {
6740 CONSTANT(10U, 0U);
6741 BASIC_BLOCK(2U, -1L)
6742 {
6743 INST(1U, Opcode::SaveState).NoVregs();
6744 INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
6745 INST(11U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).Inputs(2U, 10U);
6746 INST(9U, Opcode::Return).s32().Inputs(11U);
6747 }
6748 }
6749 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6750 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
6751
6752 GraphChecker(GetGraph()).Check();
6753 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6754 }
6755
TEST_F(PeepholesTest,MultiArrayWithLenArrayFirstLayer)6756 TEST_F(PeepholesTest, MultiArrayWithLenArrayFirstLayer)
6757 {
6758 auto class1 = reinterpret_cast<RuntimeInterface::ClassPtr>(1U);
6759 GRAPH(GetGraph())
6760 {
6761 CONSTANT(0U, 0x3U);
6762 CONSTANT(1U, 0x2U);
6763 CONSTANT(7U, 0x1U);
6764
6765 BASIC_BLOCK(2U, -1L)
6766 {
6767 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6768 INST(3U, Opcode::LoadImmediate).ref().Class(class1);
6769 INST(4U, Opcode::MultiArray)
6770 .ref()
6771 .InputsAutoType(3U, 0U, 1U, 2U); // Will be create [ [ [][] ], [ [][] ], [ [][] ] ]
6772 INST(5U, Opcode::LenArray).Inputs(4U).s32();
6773 INST(10U, Opcode::Return).s32().Inputs(5U);
6774 }
6775 }
6776
6777 auto graph = CreateEmptyGraph();
6778 GRAPH(graph)
6779 {
6780 CONSTANT(0U, 0x3U);
6781 CONSTANT(1U, 0x2U);
6782 CONSTANT(7U, 0x1U);
6783
6784 BASIC_BLOCK(2U, -1L)
6785 {
6786 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6787 INST(3U, Opcode::LoadImmediate).ref().Class(class1);
6788 INST(4U, Opcode::MultiArray)
6789 .ref()
6790 .InputsAutoType(3U, 0U, 1U, 2U); // Will be create [ [ [][] ], [ [][] ], [ [][] ] ]
6791 INST(5U, Opcode::LenArray).Inputs(4U).s32();
6792 INST(10U, Opcode::Return).s32().Inputs(0U);
6793 }
6794 }
6795 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6796 GraphChecker(GetGraph()).Check();
6797 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6798 }
6799
SRC_GRAPH(MultiArrayWithLenArraySecondLayer,Graph * graph)6800 SRC_GRAPH(MultiArrayWithLenArraySecondLayer, Graph *graph)
6801 {
6802 auto class1 = reinterpret_cast<RuntimeInterface::ClassPtr>(1U);
6803 GRAPH(graph)
6804 {
6805 PARAMETER(0U, 0x3U).s32();
6806 CONSTANT(1U, 0x2U);
6807 CONSTANT(7U, 0x1U);
6808
6809 BASIC_BLOCK(2U, -1L)
6810 {
6811 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6812 INST(3U, Opcode::LoadImmediate).ref().Class(class1);
6813 INST(4U, Opcode::MultiArray)
6814 .ref()
6815 .InputsAutoType(3U, 0U, 1U, 2U); // Will be create [ [ [][] ], [ [][] ], [ [][] ] ]
6816 INST(5U, Opcode::LenArray).Inputs(4U).s32();
6817 INST(11U, Opcode::LoadArray).ref().Inputs(4U, 7U);
6818 INST(12U, Opcode::NullCheck).ref().Inputs(11U, 2U);
6819 INST(13U, Opcode::LenArray).Inputs(12U).s32();
6820 INST(14U, Opcode::Add).Inputs(5U, 13U).s32();
6821 INST(10U, Opcode::Return).s32().Inputs(14U);
6822 }
6823 }
6824 }
6825
OUT_GRAPH(MultiArrayWithLenArraySecondLayer,Graph * graph)6826 OUT_GRAPH(MultiArrayWithLenArraySecondLayer, Graph *graph)
6827 {
6828 auto class1 = reinterpret_cast<RuntimeInterface::ClassPtr>(1U);
6829 GRAPH(graph)
6830 {
6831 PARAMETER(0U, 0x3U).s32();
6832 CONSTANT(1U, 0x2U);
6833 CONSTANT(7U, 0x1U);
6834
6835 BASIC_BLOCK(2U, -1L)
6836 {
6837 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6838 INST(3U, Opcode::LoadImmediate).ref().Class(class1);
6839 INST(4U, Opcode::MultiArray)
6840 .ref()
6841 .InputsAutoType(3U, 0U, 1U, 2U); // Will be create [ [ [][] ], [ [][] ], [ [][] ] ]
6842 INST(5U, Opcode::LenArray).Inputs(4U).s32();
6843 INST(11U, Opcode::LoadArray).ref().Inputs(4U, 7U);
6844 INST(12U, Opcode::NullCheck).ref().Inputs(11U, 2U);
6845 INST(13U, Opcode::LenArray).Inputs(12U).s32();
6846 INST(14U, Opcode::Add).Inputs(0U, 1U).s32();
6847 INST(10U, Opcode::Return).s32().Inputs(14U);
6848 }
6849 }
6850 }
6851
TEST_F(PeepholesTest,MultiArrayWithLenArraySecondLayer)6852 TEST_F(PeepholesTest, MultiArrayWithLenArraySecondLayer)
6853 {
6854 src_graph::MultiArrayWithLenArraySecondLayer::CREATE(GetGraph());
6855
6856 auto graph = CreateEmptyGraph();
6857 out_graph::MultiArrayWithLenArraySecondLayer::CREATE(graph);
6858 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6859 GraphChecker(GetGraph()).Check();
6860 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6861 }
6862
SRC_GRAPH(MultiArrayWithLenArrayOfString,Graph * graph)6863 SRC_GRAPH(MultiArrayWithLenArrayOfString, Graph *graph)
6864 {
6865 auto class1 = reinterpret_cast<RuntimeInterface::ClassPtr>(1U);
6866 GRAPH(graph)
6867 {
6868 PARAMETER(0U, 0x1U).s32();
6869 CONSTANT(1U, 0x3U);
6870 PARAMETER(2U, 0x2U).s32(); // Will think, that value is 0x2
6871
6872 BASIC_BLOCK(2U, -1L)
6873 {
6874 INST(3U, Opcode::SaveState);
6875 INST(4U, Opcode::LoadImmediate).ref().Class(class1);
6876 INST(5U, Opcode::MultiArray)
6877 .ref()
6878 .InputsAutoType(4U, 1U, 2U,
6879 3U); // Will be create [ [ String, String ], [ String, String ], [ String, String ] ]
6880 INST(6U, Opcode::LenArray).Inputs(5U).s32();
6881
6882 INST(7U, Opcode::LoadArray).ref().Inputs(5U, 0U); // Loaded: [ String, String ]
6883 INST(8U, Opcode::NullCheck).ref().Inputs(7U, 3U);
6884 INST(9U, Opcode::LenArray).Inputs(8U).s32();
6885
6886 INST(10U, Opcode::LoadArray).ref().Inputs(8U, 0U); // Loaded: String
6887 INST(11U, Opcode::NullCheck).ref().Inputs(10U, 3U);
6888 INST(12U, Opcode::LenArray).Inputs(11U).s32(); // Length of String
6889
6890 INST(13U, Opcode::Add).Inputs(9U, 6U).s32();
6891 INST(14U, Opcode::Add).Inputs(13U, 12U).s32();
6892 INST(15U, Opcode::Return).s32().Inputs(14U);
6893 }
6894 }
6895 }
6896
OUT_GRAPH(MultiArrayWithLenArrayOfString,Graph * graph)6897 OUT_GRAPH(MultiArrayWithLenArrayOfString, Graph *graph)
6898 {
6899 auto class1 = reinterpret_cast<RuntimeInterface::ClassPtr>(1U);
6900 GRAPH(graph)
6901 {
6902 PARAMETER(0U, 0x1U).s32();
6903 CONSTANT(1U, 0x3U);
6904 PARAMETER(2U, 0x2U).s32(); // Will think, that value is 0x2
6905
6906 BASIC_BLOCK(2U, -1L)
6907 {
6908 INST(3U, Opcode::SaveState);
6909 INST(4U, Opcode::LoadImmediate).ref().Class(class1);
6910 INST(5U, Opcode::MultiArray)
6911 .ref()
6912 .InputsAutoType(4U, 1U, 2U,
6913 3U); // Will be create [ [ String, String ], [ String, String ], [ String, String ] ]
6914 INST(6U, Opcode::LenArray).Inputs(5U).s32();
6915
6916 INST(7U, Opcode::LoadArray).ref().Inputs(5U, 0U); // Loaded: [ String, String ]
6917 INST(8U, Opcode::NullCheck).ref().Inputs(7U, 3U);
6918 INST(9U, Opcode::LenArray).Inputs(8U).s32();
6919
6920 INST(10U, Opcode::LoadArray).ref().Inputs(8U, 0U); // Loaded: String
6921 INST(11U, Opcode::NullCheck).ref().Inputs(10U, 3U);
6922 INST(12U, Opcode::LenArray).Inputs(11U).s32(); // Length of String
6923
6924 INST(13U, Opcode::Add).Inputs(2U, 1U).s32();
6925 INST(14U, Opcode::Add).Inputs(13U, 12U).s32();
6926 INST(15U, Opcode::Return).s32().Inputs(14U);
6927 }
6928 }
6929 }
6930
TEST_F(PeepholesTest,MultiArrayWithLenArrayOfString)6931 TEST_F(PeepholesTest, MultiArrayWithLenArrayOfString)
6932 {
6933 src_graph::MultiArrayWithLenArrayOfString::CREATE(GetGraph());
6934
6935 auto graph = CreateEmptyGraph();
6936 out_graph::MultiArrayWithLenArrayOfString::CREATE(graph);
6937
6938 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6939 GraphChecker(GetGraph()).Check();
6940 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6941 }
6942
TEST_F(PeepholesTest,RemoveDoubleXor)6943 TEST_F(PeepholesTest, RemoveDoubleXor)
6944 {
6945 GRAPH(GetGraph())
6946 {
6947 PARAMETER(0U, 0U).i32(); // arg 0
6948 CONSTANT(1U, 1U).i64(); // Constant i64 0x1
6949 BASIC_BLOCK(2U, -1L)
6950 {
6951 INST(2U, Opcode::Xor).i32().Inputs(0U, 1U);
6952 INST(3U, Opcode::Xor).i32().Inputs(2U, 1U);
6953 INST(4U, Opcode::Return).b().Inputs(3U);
6954 }
6955 }
6956 ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6957 GetGraph()->RunPass<Cleanup>();
6958 auto graph = CreateEmptyGraph();
6959 GRAPH(graph)
6960 {
6961 PARAMETER(0U, 0U).i32(); // arg 0
6962 BASIC_BLOCK(2U, -1L)
6963 {
6964 INST(4U, Opcode::Return).b().Inputs(0U);
6965 }
6966 }
6967 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6968 }
6969
TEST_F(PeepholesTest,RemoveDoubleXorNeg1)6970 TEST_F(PeepholesTest, RemoveDoubleXorNeg1)
6971 {
6972 GRAPH(GetGraph())
6973 {
6974 PARAMETER(0U, 0U).i32(); // arg 0
6975 PARAMETER(1U, 1U).i32(); // arg 1 (non-const input)
6976 BASIC_BLOCK(2U, -1L)
6977 {
6978 INST(2U, Opcode::Xor).i32().Inputs(0U, 1U);
6979 INST(3U, Opcode::Xor).i32().Inputs(2U, 1U);
6980 INST(4U, Opcode::Return).b().Inputs(3U);
6981 }
6982 }
6983 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
6984 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
6985 GraphChecker(GetGraph()).Check();
6986 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
6987 }
6988
TEST_F(PeepholesTest,RemoveDoubleXorNeg2)6989 TEST_F(PeepholesTest, RemoveDoubleXorNeg2)
6990 {
6991 GRAPH(GetGraph())
6992 {
6993 PARAMETER(0U, 0U).i32(); // arg 0
6994 CONSTANT(1U, 1U).i64(); // Constant i64 0x1
6995 BASIC_BLOCK(2U, -1L)
6996 {
6997 INST(2U, Opcode::Add).i32().Inputs(0U, 1U); // Non-Xor input of the second Xor
6998 INST(3U, Opcode::Xor).i32().Inputs(2U, 1U);
6999 INST(4U, Opcode::Return).b().Inputs(3U);
7000 }
7001 }
7002 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
7003 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
7004 GraphChecker(GetGraph()).Check();
7005 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
7006 }
7007
TEST_F(PeepholesTest,RemoveDoubleXorNeg3)7008 TEST_F(PeepholesTest, RemoveDoubleXorNeg3)
7009 {
7010 GRAPH(GetGraph())
7011 {
7012 PARAMETER(0U, 0U).i32(); // arg 0
7013 CONSTANT(1U, 1U).i64(); // Constant i64 0x1
7014 BASIC_BLOCK(2U, -1L)
7015 {
7016 INST(2U, Opcode::Xor).i32().Inputs(0U, 1U);
7017 INST(3U, Opcode::Xor).i32().Inputs(2U, 1U);
7018 INST(4U, Opcode::Add).i32().Inputs(2U, 0U); // Extra user of first Xor
7019 INST(5U, Opcode::Return).b().Inputs(3U);
7020 }
7021 }
7022 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
7023 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
7024 GraphChecker(GetGraph()).Check();
7025 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
7026 }
7027
TEST_F(PeepholesTest,RemoveDoubleXorNeg4)7028 TEST_F(PeepholesTest, RemoveDoubleXorNeg4)
7029 {
7030 GRAPH(GetGraph())
7031 {
7032 PARAMETER(0U, 0U).i32(); // arg 0
7033 CONSTANT(1U, 1U).i64(); // Constant i64 0x1
7034 CONSTANT(2U, 2U).i64(); // Another constant i64 0x2
7035 BASIC_BLOCK(2U, -1L)
7036 {
7037 INST(3U, Opcode::Xor).i32().Inputs(0U, 1U);
7038 INST(4U, Opcode::Xor).i32().Inputs(3U, 2U);
7039 INST(5U, Opcode::Return).b().Inputs(4U);
7040 }
7041 }
7042 auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
7043 ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
7044 GraphChecker(GetGraph()).Check();
7045 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
7046 }
7047
7048 // NOLINTEND(readability-magic-numbers)
7049
7050 } // namespace ark::compiler
7051