21 #include <gtest/gtest.h>
31 TEST(LoopStrengthReductionTests, SimpleArithmeticCandidateOperation)
43 auto & graph = rvsdgModule.
Rvsdg();
50 const auto memoryState = theta->AddLoopVar(mem);
51 const auto lv1 = theta->AddLoopVar(c0.output(0));
54 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c2.output(0) }, 32);
57 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, c3.output(0) }, 32);
61 { mulNode.output(0), memoryState.pre },
67 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode.output(0), c5.output(0) }, 32);
68 const auto matchResult =
71 theta->set_predicate(matchResult);
72 lv1.post->divert_to(addNode.output(0));
73 memoryState.post->divert_to(testOperation->output(0));
80 const auto numLoopVarsBefore = theta->GetLoopVars().size();
88 const auto numLoopVarsAfter = theta->GetLoopVars().size();
93 EXPECT_EQ(numLoopVarsAfter, numLoopVarsBefore + 1);
95 auto newIV = theta->GetLoopVars()[numLoopVarsAfter - 1];
98 const auto & IVInputNode =
99 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV.input->origin());
100 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(IVInputNode->GetOperation()));
101 const auto & constantOperation =
103 EXPECT_NE(constantOperation,
nullptr);
104 EXPECT_EQ(constantOperation->Representation().to_uint(), 0u);
107 const auto & IVPostOrigin =
108 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV.post->origin());
109 EXPECT_TRUE(jlm::rvsdg::is<IntegerAddOperation>(IVPostOrigin->GetOperation()));
112 EXPECT_EQ(IVPostOrigin->input(0)->origin(), newIV.pre);
115 const auto & addRhsInputNode =
116 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*IVPostOrigin->input(1)->origin());
117 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(addRhsInputNode));
118 const auto & rhsConstantOperation =
120 EXPECT_NE(rhsConstantOperation,
nullptr);
121 EXPECT_EQ(rhsConstantOperation->Representation().to_uint(), 6u);
124 EXPECT_EQ(testOperation->input(0)->origin(), newIV.pre);
127 TEST(LoopStrengthReductionTests, CandidateOperationDependentOnInvalidInductionVariable)
138 auto & graph = rvsdgModule.
Rvsdg();
145 const auto memoryState = theta->AddLoopVar(mem);
146 const auto lv1 = theta->AddLoopVar(c0.output(0));
149 auto & mulNode1 = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, c2.output(0) }, 32);
152 auto & mulNode2 = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, c3.output(0) }, 32);
156 { mulNode2.output(0), memoryState.pre },
157 { memoryStateType });
162 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ mulNode1.output(0), c5.output(0) }, 32);
163 const auto matchResult =
166 theta->set_predicate(matchResult);
167 lv1.post->divert_to(mulNode1.output(0));
168 memoryState.post->divert_to(testOperation->output(0));
175 const auto numLoopVarsBefore = theta->GetLoopVars().size();
183 const auto numLoopVarsAfter = theta->GetLoopVars().size();
188 EXPECT_EQ(numLoopVarsAfter, numLoopVarsBefore);
191 EXPECT_EQ(testOperation->input(0)->origin(), mulNode2.output(0));
194 TEST(LoopStrengthReductionTests, NestedArithmeticCandidateOperation)
209 auto & graph = rvsdgModule.
Rvsdg();
216 const auto memoryState = theta->AddLoopVar(mem);
217 const auto lv1 = theta->AddLoopVar(c0.output(0));
220 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c2.output(0) }, 32);
223 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, c3.output(0) }, 32);
227 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ mulNode.output(0), c1.output(0) }, 32);
231 { addNode2.output(0), memoryState.pre },
232 { memoryStateType });
237 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode1.output(0), c5.output(0) }, 32);
238 const auto matchResult =
241 theta->set_predicate(matchResult);
242 lv1.post->divert_to(addNode1.output(0));
243 memoryState.post->divert_to(testOperation->output(0));
250 const auto numLoopVarsBefore = theta->GetLoopVars().size();
258 const auto numLoopVarsAfter = theta->GetLoopVars().size();
263 EXPECT_EQ(numLoopVarsAfter, numLoopVarsBefore + 1);
265 auto newIV = theta->GetLoopVars()[numLoopVarsAfter - 1];
268 const auto & IVInputNode =
269 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV.input->origin());
270 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(IVInputNode->GetOperation()));
271 const auto & constantOperation =
273 EXPECT_NE(constantOperation,
nullptr);
274 EXPECT_EQ(constantOperation->Representation().to_uint(), 1u);
277 const auto & IVPostOrigin =
278 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV.post->origin());
279 EXPECT_TRUE(jlm::rvsdg::is<IntegerAddOperation>(IVPostOrigin->GetOperation()));
281 EXPECT_EQ(IVPostOrigin->input(0)->origin(), newIV.pre);
283 const auto & addRhsInputNode =
284 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*IVPostOrigin->input(1)->origin());
285 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(addRhsInputNode));
286 const auto & rhsConstantOperation =
288 EXPECT_NE(rhsConstantOperation,
nullptr);
289 EXPECT_EQ(rhsConstantOperation->Representation().to_uint(), 6u);
292 EXPECT_EQ(testOperation->input(0)->origin(), newIV.pre);
295 TEST(LoopStrengthReductionTests, NestedArithmeticCandidateOperationWithUsersForBoth)
308 auto & graph = rvsdgModule.
Rvsdg();
315 const auto memoryState = theta->AddLoopVar(mem);
316 const auto lv1 = theta->AddLoopVar(c0.output(0));
319 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c2.output(0) }, 32);
322 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, c3.output(0) }, 32);
326 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ mulNode.output(0), c1.output(0) }, 32);
330 { mulNode.output(0), memoryState.pre },
331 { memoryStateType });
335 { addNode2.output(0), testOperation1->output(0) },
336 { memoryStateType });
341 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode1.output(0), c5.output(0) }, 32);
342 const auto matchResult =
345 theta->set_predicate(matchResult);
346 lv1.post->divert_to(addNode1.output(0));
347 memoryState.post->divert_to(testOperation2->output(0));
354 const auto numLoopVarsBefore = theta->GetLoopVars().size();
362 const auto numLoopVarsAfter = theta->GetLoopVars().size();
367 EXPECT_EQ(numLoopVarsAfter, numLoopVarsBefore + 2);
369 auto newIV1 = theta->GetLoopVars()[numLoopVarsAfter - 1];
370 auto newIV2 = theta->GetLoopVars()[numLoopVarsAfter - 2];
373 const auto & IV1InputNode =
374 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV1.input->origin());
375 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(IV1InputNode->GetOperation()));
376 auto constantOperation1 =
378 EXPECT_NE(constantOperation1,
nullptr);
379 EXPECT_EQ(constantOperation1->Representation().to_uint(), 1u);
381 const auto & IV2InputNode =
382 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV2.input->origin());
383 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(IV2InputNode->GetOperation()));
384 auto constantOperation2 =
386 EXPECT_NE(constantOperation2,
nullptr);
387 EXPECT_EQ(constantOperation2->Representation().to_uint(), 0u);
390 const auto & IV1PostOrigin =
391 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV1.post->origin());
392 EXPECT_TRUE(jlm::rvsdg::is<IntegerAddOperation>(IV1PostOrigin->GetOperation()));
394 EXPECT_EQ(IV1PostOrigin->input(0)->origin(), newIV1.pre);
396 const auto & addRhsInputNode1 =
397 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*IV1PostOrigin->input(1)->origin());
398 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(addRhsInputNode1));
399 const auto & rhsConstantOperation1 =
401 EXPECT_NE(rhsConstantOperation1,
nullptr);
402 EXPECT_EQ(rhsConstantOperation1->Representation().to_uint(), 6u);
404 const auto & IV2PostOrigin =
405 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV2.post->origin());
406 EXPECT_TRUE(jlm::rvsdg::is<IntegerAddOperation>(IV2PostOrigin->GetOperation()));
408 EXPECT_EQ(IV2PostOrigin->input(0)->origin(), newIV2.pre);
410 const auto & addRhsInputNode2 =
411 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*IV2PostOrigin->input(1)->origin());
412 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(addRhsInputNode2));
413 const auto & rhsConstantOperation2 =
415 EXPECT_NE(rhsConstantOperation2,
nullptr);
416 EXPECT_EQ(rhsConstantOperation2->Representation().to_uint(), 6u);
419 EXPECT_EQ(testOperation1->input(0)->origin(), newIV2.pre);
420 EXPECT_EQ(testOperation2->input(0)->origin(), newIV1.pre);
423 TEST(LoopStrengthReductionTests, SimpleGEPCandidateOperation)
438 auto & graph = rvsdgModule.
Rvsdg();
446 const auto memoryState = theta->AddLoopVar(mem);
447 const auto lv1 = theta->AddLoopVar(c0_1.output(0));
448 const auto lv2 = theta->AddLoopVar(arrPtr);
451 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c2.output(0) }, 32);
454 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, c3.output(0) }, 32);
464 jlm::rvsdg::CreateOpNode<IntegerSubOperation>({ loadOutputs[0], c2.output(0) }, 32);
471 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode1.output(0), c5.output(0) }, 32);
472 const auto matchResult =
475 lv1.post->divert_to(addNode1.output(0));
476 memoryState.post->divert_to(storeOutputs[0]);
477 theta->set_predicate(matchResult);
484 const auto numLoopVarsBefore = theta->GetLoopVars().size();
486 std::vector<jlm::rvsdg::Input *> oldGepNodeUsers;
494 const auto numLoopVarsAfter = theta->GetLoopVars().size();
499 EXPECT_EQ(numLoopVarsAfter, numLoopVarsBefore + 1);
500 auto newIV = theta->GetLoopVars()[numLoopVarsAfter - 1];
503 const auto & IVPostOrigin =
504 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV.post->origin());
505 EXPECT_TRUE(jlm::rvsdg::is<GetElementPtrOperation>(IVPostOrigin->GetOperation()));
506 const auto & gepOperation =
508 EXPECT_NE(gepOperation,
nullptr);
512 EXPECT_EQ(IVPostOrigin->input(0)->origin(), newIV.pre);
514 const auto & gepIndexInputNode =
515 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*IVPostOrigin->input(1)->origin());
516 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(gepIndexInputNode));
517 const auto & constantOperation =
519 EXPECT_NE(constantOperation,
nullptr);
520 EXPECT_EQ(constantOperation->Representation().nbits(), 64u);
521 EXPECT_EQ(constantOperation->Representation().to_uint(), 24u);
524 auto loadNode = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*loadOutputs[0]);
525 EXPECT_NE(loadNode,
nullptr);
526 EXPECT_TRUE(jlm::rvsdg::is<LoadNonVolatileOperation>(loadNode->GetOperation()));
527 EXPECT_EQ(LoadOperation::AddressInput(*loadNode).origin(), newIV.pre);
529 auto storeNode = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*storeOutputs[0]);
530 EXPECT_NE(storeNode,
nullptr);
531 EXPECT_TRUE(jlm::rvsdg::is<StoreNonVolatileOperation>(storeNode->GetOperation()));
532 EXPECT_EQ(StoreOperation::AddressInput(*storeNode).origin(), newIV.pre);
535 TEST(LoopStrengthReductionTests, GEPCandidateOperationWithNAryStart)
551 auto & graph = rvsdgModule.
Rvsdg();
559 const auto memoryState = theta->AddLoopVar(mem);
560 const auto lv1 = theta->AddLoopVar(c0_1.output(0));
561 const auto lv2 = theta->AddLoopVar(arrPtr);
564 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, c2.output(0) }, 32);
567 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, c3.output(0) }, 32);
570 jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ mulNode.output(0), c4.output(0) }, 32);
584 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode1.output(0), c5.output(0) }, 32);
585 const auto matchResult =
588 lv1.post->divert_to(addNode1.output(0));
589 memoryState.post->divert_to(storeOutputs[0]);
590 theta->set_predicate(matchResult);
597 const auto numLoopVarsBefore = theta->GetLoopVars().size();
599 std::vector<jlm::rvsdg::Input *> oldGepNodeUsers;
607 const auto numLoopVarsAfter = theta->GetLoopVars().size();
612 EXPECT_EQ(numLoopVarsAfter, numLoopVarsBefore + 1);
613 auto newIV = theta->GetLoopVars()[numLoopVarsAfter - 1];
617 const auto & newIVInputNode =
618 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV.input->origin());
619 EXPECT_TRUE(jlm::rvsdg::is<GetElementPtrOperation>(newIVInputNode->GetOperation()));
620 auto lhs = newIVInputNode->input(0)->origin();
621 auto rhs = newIVInputNode->input(1)->origin();
622 EXPECT_EQ(lhs, arrPtr);
623 const auto rhsNode = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*rhs);
624 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(rhsNode->GetOperation()));
625 const auto & constantOperation =
627 EXPECT_NE(constantOperation,
nullptr);
628 EXPECT_EQ(constantOperation->Representation().to_uint(), 16u);
631 const auto & IVPostOrigin =
632 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV.post->origin());
633 EXPECT_TRUE(jlm::rvsdg::is<GetElementPtrOperation>(IVPostOrigin->GetOperation()));
634 const auto & stepGepOperation =
636 EXPECT_NE(stepGepOperation,
nullptr);
641 const auto & gepIndexInputNode =
642 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*IVPostOrigin->input(1)->origin());
643 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(gepIndexInputNode));
644 const auto & indexConstantOperation =
646 EXPECT_NE(indexConstantOperation,
nullptr);
647 EXPECT_EQ(indexConstantOperation->Representation().nbits(), 64u);
648 EXPECT_EQ(indexConstantOperation->Representation().to_uint(), 24u);
651 auto storeNode = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*storeOutputs[0]);
652 EXPECT_NE(storeNode,
nullptr);
653 EXPECT_TRUE(jlm::rvsdg::is<StoreNonVolatileOperation>(storeNode->GetOperation()));
654 EXPECT_EQ(StoreOperation::AddressInput(*storeNode).origin(), newIV.pre);
657 TEST(LoopStrengthReductionTests, CandidateOperationInNestedLoopTest)
669 auto & graph = rvsdgModule.
Rvsdg();
676 const auto memoryState1 = theta1->AddLoopVar(mem);
677 const auto lv1_1 = theta1->AddLoopVar(c0.output(0));
680 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1_1.pre, c1.output(0) }, 32);
684 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode1.output(0), c5.output(0) }, 32);
685 const auto matchResult1 =
688 theta1->set_predicate(matchResult1);
689 lv1_1.post->divert_to(addNode1.output(0));
693 const auto lv1_2 = theta2->AddLoopVar(lv1_1.pre);
694 const auto lv2 = theta2->AddLoopVar(c1.output(0));
695 const auto memoryState2 = theta2->AddLoopVar(memoryState1.pre);
697 const auto & c2 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 2);
698 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, c2.output(0) }, 32);
700 const auto & c3 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 3);
701 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1_2.pre, c3.output(0) }, 32);
703 const auto & c10 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 10);
705 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode2.output(0), c10.output(0) }, 32);
706 const auto matchResult2 =
711 { mulNode.output(0), memoryState2.pre },
712 { memoryStateType });
714 theta2->set_predicate(matchResult2);
715 lv2.post->divert_to(addNode2.output(0));
716 memoryState2.post->divert_to(testOperation->output(0));
718 memoryState1.post->divert_to(memoryState2.output);
724 const auto outerNumLoopVarsBefore = theta1->GetLoopVars().size();
725 const auto innerNumLoopVarsBefore = theta2->GetLoopVars().size();
733 const auto outerNumLoopVarsAfter = theta1->GetLoopVars().size();
734 const auto innerNumLoopVarsAfter = theta2->GetLoopVars().size();
739 EXPECT_EQ(outerNumLoopVarsAfter, outerNumLoopVarsBefore + 1);
740 EXPECT_EQ(innerNumLoopVarsAfter, innerNumLoopVarsBefore + 1);
742 auto outerNewIV = theta1->GetLoopVars()[outerNumLoopVarsAfter - 1];
743 auto innerNewIV = theta2->GetLoopVars()[innerNumLoopVarsAfter - 1];
746 const auto & outerIVInputNode =
747 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerNewIV.input->origin());
748 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(outerIVInputNode->GetOperation()));
749 const auto & constantOperation =
751 EXPECT_NE(constantOperation,
nullptr);
752 EXPECT_EQ(constantOperation->Representation().to_uint(), 0u);
755 const auto & outerIVPostOrigin =
756 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerNewIV.post->origin());
757 EXPECT_TRUE(jlm::rvsdg::is<IntegerAddOperation>(outerIVPostOrigin->GetOperation()));
759 EXPECT_EQ(outerIVPostOrigin->input(0)->origin(), outerNewIV.pre);
761 const auto & addRhsInputNode =
762 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerIVPostOrigin->input(1)->origin());
763 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(addRhsInputNode));
764 const auto & rhsConstantOperation =
766 EXPECT_NE(rhsConstantOperation,
nullptr);
767 EXPECT_EQ(rhsConstantOperation->Representation().to_uint(), 3u);
770 EXPECT_EQ(innerNewIV.input->origin(), outerNewIV.pre);
772 EXPECT_EQ(innerNewIV.post->origin(), innerNewIV.pre);
775 EXPECT_EQ(testOperation->input(0)->origin(), innerNewIV.pre);
778 TEST(LoopStrengthReductionTests, CandidateOperationInNestedLoopWithGammaTest)
791 auto & graph = rvsdgModule.
Rvsdg();
798 auto ev1 = gamma1->AddEntryVar(c0.output(0));
799 auto mem1 = gamma1->AddEntryVar(m);
803 const auto memoryState1 = theta1->AddLoopVar(mem1.branchArgument[1]);
804 const auto lv1_1 = theta1->AddLoopVar(ev1.branchArgument[1]);
807 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1_1.pre, c1.output(0) }, 32);
811 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode1.output(0), c5.output(0) }, 32);
812 const auto matchResult1 =
815 theta1->set_predicate(matchResult1);
816 lv1_1.post->divert_to(addNode1.output(0));
818 const auto & c10 = IntegerConstantOperation::Create(*theta1->subregion(), 32, 10);
820 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ c1.output(0), c10.output(0) }, 32);
821 const auto matchResult2 =
825 auto ev2 = gamma2->AddEntryVar(c1.output(0));
826 auto mem2 = gamma2->AddEntryVar(memoryState1.pre);
827 auto ev3 = gamma2->AddEntryVar(lv1_1.pre);
831 const auto lv2 = theta2->AddLoopVar(ev2.branchArgument[1]);
832 const auto lv1_2 = theta2->AddLoopVar(ev3.branchArgument[1]);
833 const auto memoryState2 = theta2->AddLoopVar(mem2.branchArgument[1]);
835 const auto & c2 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 2);
836 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, c2.output(0) }, 32);
838 const auto & c3 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 3);
839 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1_2.pre, c3.output(0) }, 32);
841 const auto & c10_2 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 10);
843 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode2.output(0), c10_2.output(0) }, 32);
844 const auto matchResult3 =
849 { mulNode.output(0), memoryState2.pre },
850 { memoryStateType });
852 theta2->set_predicate(matchResult3);
853 lv2.post->divert_to(addNode2.output(0));
854 memoryState2.post->divert_to(testOperation->output(0));
856 auto exitVar1 = gamma2->AddExitVar({ mem2.branchArgument[0], memoryState2.output });
857 memoryState1.post->divert_to(exitVar1.output);
858 auto exitVar2 = gamma1->AddExitVar({ mem1.branchArgument[0], memoryState1.output });
865 const auto outerNumLoopVarsBefore = theta1->GetLoopVars().size();
866 const auto innerNumLoopVarsBefore = theta2->GetLoopVars().size();
868 const auto outerNumEntryVarsBefore = gamma1->GetEntryVars().size();
869 const auto innerNumEntryVarsBefore = gamma2->GetEntryVars().size();
877 const auto outerNumLoopVarsAfter = theta1->GetLoopVars().size();
878 const auto innerNumLoopVarsAfter = theta2->GetLoopVars().size();
880 const auto outerNumEntryVarsAfter = gamma1->GetEntryVars().size();
881 const auto innerNumEntryVarsAfter = gamma2->GetEntryVars().size();
886 EXPECT_EQ(outerNumLoopVarsAfter, outerNumLoopVarsBefore + 1);
887 EXPECT_EQ(innerNumLoopVarsAfter, innerNumLoopVarsBefore + 1);
890 EXPECT_EQ(innerNumEntryVarsAfter, innerNumEntryVarsBefore + 1);
891 EXPECT_EQ(outerNumEntryVarsAfter, outerNumEntryVarsBefore);
893 auto outerNewIV = theta1->GetLoopVars()[outerNumLoopVarsAfter - 1];
894 auto innerNewIV = theta2->GetLoopVars()[innerNumLoopVarsAfter - 1];
897 const auto & outerIVInputNode =
898 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerNewIV.input->origin());
899 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(outerIVInputNode->GetOperation()));
900 const auto & constantOperation =
902 EXPECT_NE(constantOperation,
nullptr);
903 EXPECT_EQ(constantOperation->Representation().to_uint(), 0u);
906 const auto & outerIVPostOrigin =
907 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerNewIV.post->origin());
908 EXPECT_TRUE(jlm::rvsdg::is<IntegerAddOperation>(outerIVPostOrigin->GetOperation()));
910 EXPECT_EQ(outerIVPostOrigin->input(0)->origin(), outerNewIV.pre);
912 const auto & addRhsInputNode =
913 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerIVPostOrigin->input(1)->origin());
914 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(addRhsInputNode));
915 const auto & rhsConstantOperation =
917 EXPECT_NE(rhsConstantOperation,
nullptr);
918 EXPECT_EQ(rhsConstantOperation->Representation().to_uint(), 3u);
921 auto innerNewEV = gamma2->GetEntryVars()[innerNumEntryVarsAfter - 1];
923 EXPECT_EQ(innerNewEV.input->origin(), outerNewIV.pre);
926 EXPECT_EQ(innerNewIV.input->origin(), innerNewEV.branchArgument[1]);
929 EXPECT_EQ(innerNewIV.post->origin(), innerNewIV.pre);
932 EXPECT_EQ(testOperation->input(0)->origin(), innerNewIV.pre);
935 TEST(LoopStrengthReductionTests, CandidateOperationInThreeLevelNestedLoopTest)
946 auto & graph = rvsdgModule.
Rvsdg();
953 const auto memoryState1 = theta1->AddLoopVar(mem);
954 const auto lv1_1 = theta1->AddLoopVar(c0.output(0));
957 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1_1.pre, c1.output(0) }, 32);
961 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode1.output(0), c5.output(0) }, 32);
962 const auto matchResult1 =
965 theta1->set_predicate(matchResult1);
966 lv1_1.post->divert_to(addNode1.output(0));
970 const auto lv1_2 = theta2->AddLoopVar(lv1_1.pre);
971 const auto lv2 = theta2->AddLoopVar(c1.output(0));
972 const auto memoryState2 = theta2->AddLoopVar(memoryState1.pre);
974 const auto & c2 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 2);
975 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv2.pre, c2.output(0) }, 32);
977 const auto & c10 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 10);
979 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode2.output(0), c10.output(0) }, 32);
980 const auto matchResult2 =
983 theta2->set_predicate(matchResult2);
984 lv2.post->divert_to(addNode2.output(0));
988 const auto lv1_3 = theta3->AddLoopVar(lv1_2.pre);
989 const auto lv3 = theta3->AddLoopVar(c2.output(0));
990 const auto memoryState3 = theta3->AddLoopVar(memoryState2.pre);
992 const auto & c4 = IntegerConstantOperation::Create(*theta3->subregion(), 32, 4);
993 auto & addNode3 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv3.pre, c4.output(0) }, 32);
995 const auto & c3 = IntegerConstantOperation::Create(*theta3->subregion(), 32, 3);
996 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1_3.pre, c3.output(0) }, 32);
998 const auto & c20 = IntegerConstantOperation::Create(*theta3->subregion(), 32, 20);
1000 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode3.output(0), c20.output(0) }, 32);
1001 const auto matchResult3 =
1005 theta3->subregion(),
1006 { mulNode.output(0), memoryState3.pre },
1007 { memoryStateType });
1009 theta3->set_predicate(matchResult3);
1010 lv3.post->divert_to(addNode3.output(0));
1011 memoryState3.post->divert_to(testOperation->output(0));
1013 lv1_2.post->divert_to(lv1_3.output);
1014 memoryState2.post->divert_to(memoryState3.output);
1016 memoryState1.post->divert_to(memoryState2.output);
1022 const auto outerNumLoopVarsBefore = theta1->GetLoopVars().size();
1023 const auto middleNumLoopVarsBefore = theta2->GetLoopVars().size();
1024 const auto innerNumLoopVarsBefore = theta3->GetLoopVars().size();
1032 const auto outerNumLoopVarsAfter = theta1->GetLoopVars().size();
1033 const auto middleNumLoopVarsAfter = theta2->GetLoopVars().size();
1034 const auto innerNumLoopVarsAfter = theta3->GetLoopVars().size();
1039 EXPECT_EQ(outerNumLoopVarsAfter, outerNumLoopVarsBefore + 1);
1040 EXPECT_EQ(middleNumLoopVarsAfter, middleNumLoopVarsBefore + 1);
1041 EXPECT_EQ(innerNumLoopVarsAfter, innerNumLoopVarsBefore + 1);
1043 auto outerNewIV = theta1->GetLoopVars()[outerNumLoopVarsAfter - 1];
1044 auto middleNewIV = theta2->GetLoopVars()[middleNumLoopVarsAfter - 1];
1045 auto innerNewIV = theta3->GetLoopVars()[innerNumLoopVarsAfter - 1];
1048 const auto & outerIVInputNode =
1049 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerNewIV.input->origin());
1050 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(outerIVInputNode->GetOperation()));
1051 const auto & constantOperation =
1053 EXPECT_NE(constantOperation,
nullptr);
1054 EXPECT_EQ(constantOperation->Representation().to_uint(), 0u);
1057 const auto & outerIVPostOrigin =
1058 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerNewIV.post->origin());
1059 EXPECT_TRUE(jlm::rvsdg::is<IntegerAddOperation>(outerIVPostOrigin->GetOperation()));
1061 EXPECT_EQ(outerIVPostOrigin->input(0)->origin(), outerNewIV.pre);
1063 const auto & addRhsInputNode =
1064 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerIVPostOrigin->input(1)->origin());
1065 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(addRhsInputNode));
1066 const auto & rhsConstantOperation =
1068 EXPECT_NE(rhsConstantOperation,
nullptr);
1069 EXPECT_EQ(rhsConstantOperation->Representation().to_uint(), 3u);
1072 EXPECT_EQ(middleNewIV.input->origin(), outerNewIV.pre);
1074 EXPECT_EQ(middleNewIV.post->origin(), middleNewIV.pre);
1077 EXPECT_EQ(innerNewIV.input->origin(), middleNewIV.pre);
1079 EXPECT_EQ(innerNewIV.post->origin(), innerNewIV.pre);
1082 EXPECT_EQ(testOperation->input(0)->origin(), innerNewIV.pre);
1085 TEST(LoopStrengthReductionTests, CandidateOperationWithInitTest)
1098 auto & graph = rvsdgModule.
Rvsdg();
1105 graph.GetRootRegion(),
1110 auto cv1 = lambda->AddContextVar(*mem).inner;
1111 auto cv2 = lambda->AddContextVar(*i).inner;
1112 auto cv3 = lambda->AddContextVar(*k).inner;
1116 const auto memoryState = theta->
AddLoopVar(cv1);
1117 const auto lv1 = theta->AddLoopVar(cv2);
1118 const auto lv2 = theta->AddLoopVar(cv3);
1120 auto & addNode = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1.pre, lv2.pre }, 32);
1123 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv1.pre, c3.output(0) }, 32);
1127 { mulNode.output(0), memoryState.pre },
1128 { memoryStateType });
1133 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode.output(0), c5.output(0) }, 32);
1134 const auto matchResult =
1137 theta->set_predicate(matchResult);
1138 lv1.post->divert_to(addNode.output(0));
1139 memoryState.post->divert_to(testOperation->output(0));
1141 auto res = lambda->finalize({ memoryState.output });
1148 const auto numLoopVarsBefore = theta->GetLoopVars().size();
1156 const auto numLoopVarsAfter = theta->GetLoopVars().size();
1160 EXPECT_EQ(numLoopVarsAfter, numLoopVarsBefore + 2);
1162 auto newIV1 = theta->GetLoopVars()[numLoopVarsAfter - 1];
1163 auto newIV2 = theta->GetLoopVars()[numLoopVarsAfter - 2];
1167 const auto & IV1InputNode =
1168 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV1.input->origin());
1169 EXPECT_TRUE(jlm::rvsdg::is<IntegerMulOperation>(IV1InputNode->GetOperation()));
1170 auto lhs1 = IV1InputNode->input(0)->origin();
1171 auto rhs1 = IV1InputNode->input(1)->origin();
1172 EXPECT_EQ(lhs1, cv2);
1173 const auto rhsNode = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*rhs1);
1174 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(rhsNode->GetOperation()));
1175 const auto & constantOperation =
1177 EXPECT_NE(constantOperation,
nullptr);
1178 EXPECT_EQ(constantOperation->Representation().to_uint(), 3u);
1182 const auto & IV2InputNode =
1183 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV2.input->origin());
1184 EXPECT_TRUE(jlm::rvsdg::is<IntegerMulOperation>(IV2InputNode->GetOperation()));
1185 auto lhs2 = IV2InputNode->input(0)->origin();
1186 auto rhs2 = IV2InputNode->input(1)->origin();
1187 EXPECT_EQ(lhs2, cv3);
1188 const auto rhsNode2 = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*rhs2);
1189 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(rhsNode2->GetOperation()));
1190 const auto & constantOperation2 =
1192 EXPECT_NE(constantOperation2,
nullptr);
1193 EXPECT_EQ(constantOperation2->Representation().to_uint(), 3u);
1196 const auto & IV1PostOrigin =
1197 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*newIV1.post->origin());
1198 EXPECT_TRUE(jlm::rvsdg::is<IntegerAddOperation>(IV1PostOrigin->GetOperation()));
1200 EXPECT_EQ(IV1PostOrigin->input(0)->origin(), newIV1.pre);
1202 EXPECT_EQ(IV1PostOrigin->input(1)->origin(), newIV2.pre);
1205 EXPECT_EQ(testOperation->input(0)->origin(), newIV1.pre);
1208 TEST(LoopStrengthReductionTests, CandidateOperationWithInitAndTracingTest)
1227 auto & graph = rvsdgModule.
Rvsdg();
1232 graph.GetRootRegion(),
1237 auto cv1 = lambda->AddContextVar(*mem).inner;
1238 auto cv2 = lambda->AddContextVar(*a).inner;
1243 const auto memoryState1 = theta1->AddLoopVar(cv1);
1244 const auto lv1_1 = theta1->AddLoopVar(c0.output(0));
1245 const auto lv2_1 = theta1->AddLoopVar(cv2);
1248 auto & addNode1 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv1_1.pre, c1.output(0) }, 32);
1252 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode1.output(0), c5.output(0) }, 32);
1253 const auto matchResult1 =
1256 theta1->set_predicate(matchResult1);
1257 lv1_1.post->divert_to(addNode1.output(0));
1261 const auto lv1_2 = theta2->AddLoopVar(lv1_1.pre);
1262 const auto lv2_2 = theta2->AddLoopVar(lv2_1.pre);
1263 const auto lv3 = theta2->AddLoopVar(c1.output(0));
1264 const auto memoryState2 = theta2->AddLoopVar(memoryState1.pre);
1266 const auto & c2 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 2);
1267 auto & addNode2 = jlm::rvsdg::CreateOpNode<IntegerAddOperation>({ lv3.pre, c2.output(0) }, 32);
1269 const auto & c3 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 3);
1270 auto & mulNode = jlm::rvsdg::CreateOpNode<IntegerMulOperation>({ lv2_2.pre, c3.output(0) }, 32);
1273 jlm::rvsdg::CreateOpNode<IntegerSubOperation>({ mulNode.output(0), lv1_2.pre }, 32);
1275 const auto & c10 = IntegerConstantOperation::Create(*theta2->subregion(), 32, 10);
1277 jlm::rvsdg::CreateOpNode<IntegerSltOperation>({ addNode2.output(0), c10.output(0) }, 32);
1278 const auto matchResult2 =
1282 theta2->subregion(),
1283 { subNode.output(0), memoryState2.pre },
1284 { memoryStateType });
1286 theta2->set_predicate(matchResult2);
1287 lv3.post->divert_to(addNode2.output(0));
1288 memoryState2.post->divert_to(testOperation->output(0));
1290 memoryState1.post->divert_to(memoryState2.output);
1291 auto res = lambda->finalize({ memoryState1.output });
1297 const auto outerNumLoopVarsBefore = theta1->GetLoopVars().size();
1298 const auto innerNumLoopVarsBefore = theta2->GetLoopVars().size();
1306 const auto outerNumLoopVarsAfter = theta1->GetLoopVars().size();
1307 const auto innerNumLoopVarsAfter = theta2->GetLoopVars().size();
1312 EXPECT_EQ(outerNumLoopVarsAfter, outerNumLoopVarsBefore + 1);
1313 EXPECT_EQ(innerNumLoopVarsAfter, innerNumLoopVarsBefore + 1);
1315 auto outerNewIV = theta1->GetLoopVars()[outerNumLoopVarsAfter - 1];
1316 auto innerNewIV = theta2->GetLoopVars()[innerNumLoopVarsAfter - 1];
1320 const auto & outerIVInputNode =
1321 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerNewIV.input->origin());
1322 EXPECT_TRUE(jlm::rvsdg::is<IntegerMulOperation>(outerIVInputNode->GetOperation()));
1323 auto lhs = outerIVInputNode->input(0)->origin();
1324 auto rhs = outerIVInputNode->input(1)->origin();
1325 EXPECT_EQ(lhs, cv2);
1326 const auto rhsNode = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*rhs);
1327 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(rhsNode->GetOperation()));
1328 const auto & constantOperation =
1330 EXPECT_EQ(constantOperation->Representation().to_uint(), 3u);
1333 const auto & outerIVPostOrigin =
1334 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerNewIV.post->origin());
1335 EXPECT_TRUE(jlm::rvsdg::is<IntegerAddOperation>(outerIVPostOrigin->GetOperation()));
1337 EXPECT_EQ(outerIVPostOrigin->input(0)->origin(), outerNewIV.pre);
1339 const auto & addRhsInputNode =
1340 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*outerIVPostOrigin->input(1)->origin());
1341 EXPECT_TRUE(jlm::rvsdg::is<IntegerConstantOperation>(addRhsInputNode));
1342 const auto & rhsConstantOperation =
1344 EXPECT_EQ(rhsConstantOperation->Representation().to_int(), -1);
1347 EXPECT_EQ(innerNewIV.input->origin(), outerNewIV.pre);
1349 EXPECT_EQ(innerNewIV.post->origin(), innerNewIV.pre);
1352 EXPECT_EQ(testOperation->input(0)->origin(), innerNewIV.pre);
static jlm::util::StatisticsCollector statisticsCollector
TEST(LoopStrengthReductionTests, SimpleArithmeticCandidateOperation)
void RunLoopStrengthReduction(jlm::rvsdg::RvsdgModule &rvsdgModule)
static std::shared_ptr< const ArrayType > Create(std::shared_ptr< const Type > type, size_t nelements)
static rvsdg::Output * create(rvsdg::Output *baseAddress, const std::vector< rvsdg::Output * > &indices, std::shared_ptr< const rvsdg::Type > pointeeType)
static rvsdg::Node & Create(rvsdg::Region ®ion, IntegerValueRepresentation representation)
static std::unique_ptr< LlvmLambdaOperation > Create(std::shared_ptr< const jlm::rvsdg::FunctionType > type, std::string name, const jlm::llvm::Linkage &linkage, jlm::llvm::CallingConvention callingConvention, jlm::llvm::AttributeSet attributes)
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *state, std::shared_ptr< const rvsdg::Type > loadedType, size_t alignment)
void Run(rvsdg::RvsdgModule &rvsdgModule, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
static std::shared_ptr< const MemoryStateType > Create()
static std::shared_ptr< const PointerType > Create()
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *operand, const std::shared_ptr< const rvsdg::Type > &type)
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *state, size_t alignment)
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
static std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
static std::shared_ptr< const FunctionType > Create(std::vector< std::shared_ptr< const jlm::rvsdg::Type >> argumentTypes, std::vector< std::shared_ptr< const jlm::rvsdg::Type >> resultTypes)
static GammaNode * create(jlm::rvsdg::Output *predicate, size_t nalternatives)
static GraphExport & Create(Output &origin, std::string name)
static GraphImport & Create(Graph &graph, std::shared_ptr< const rvsdg::Type > type, std::string name)
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
static Output * Create(Output &predicate, const std::unordered_map< uint64_t, uint64_t > &mapping, const uint64_t defaultAlternative, const size_t numAlternatives)
static SimpleNode * createNode(Region *region, const std::vector< Output * > &operands, std::vector< std::shared_ptr< const Type >> resultTypes)
static ThetaNode * create(rvsdg::Region *parent)
LoopVar AddLoopVar(rvsdg::Output *origin)
Creates a new loop-carried variable.
Global memory state passed between functions.