6 #include <gtest/gtest.h>
34 TEST(StoreValueForwardingTests, NestedAllocas)
56 auto & graph = rvsdgModule.
Rvsdg();
63 { ioStateType, memoryStateType },
64 { intType, ioStateType, memoryStateType });
68 graph.GetRootRegion(),
71 const auto io0 = lambdaNode.GetFunctionArguments()[0];
72 const auto mem0 = lambdaNode.GetFunctionArguments()[1];
85 { allocaPOutputs[1], allocaAOutputs[1] },
91 *constantTwenty.output(0),
92 { storePANode.output(0), storePANode.output(1) },
98 { storeA20Node.output(0), storeA20Node.output(1) },
104 *loadPNode.output(0),
105 { loadPNode.output(1), loadPNode.output(2) },
109 lambdaNode.finalize({ loadA0Node.output(0), io0, mem0 });
121 size_t allocaCount = 0;
122 size_t storeCount = 0;
123 size_t loadCount = 0;
125 for (
auto & node : lambdaNode.subregion()->Nodes())
127 if (is<AllocaOperation>(&node))
129 else if (is<StoreOperation>(&node))
131 else if (is<LoadOperation>(&node))
134 EXPECT_EQ(allocaCount, 0u);
135 EXPECT_EQ(storeCount, 0u);
136 EXPECT_EQ(loadCount, 0u);
139 const auto & result = *lambdaNode.GetFunctionResults()[0]->origin();
141 EXPECT_EQ(resultValue, 20);
144 TEST(StoreValueForwardingTests, GetElementPointerOffsets)
169 auto & graph = rvsdgModule.
Rvsdg();
177 { ioStateType, memoryStateType },
178 { bits64Type, bits32Type, bits32Type, ioStateType, memoryStateType });
182 graph.GetRootRegion(),
185 const auto io0 = lambdaNode.GetFunctionArguments()[0];
186 const auto mem0 = lambdaNode.GetFunctionArguments()[1];
198 *constantForty.output(0),
199 { allocaAOutputs[1] },
210 *constantTwenty.output(0),
211 { storeA40Node.output(0) },
217 { storeB20Node.output(0) },
224 { loadL1Node.output(1) },
238 { loadL1Node.output(0), loadL2Node.output(0), loadL3Node.output(0), io0, mem0 });
248 size_t storeCount = 0;
249 size_t loadCount = 0;
251 for (
auto & node : lambdaNode.subregion()->Nodes())
253 if (is<StoreOperation>(&node))
255 else if (is<LoadOperation>(&node))
258 EXPECT_EQ(storeCount, 2u);
259 EXPECT_EQ(loadCount, 1u);
262 const auto results = lambdaNode.GetFunctionResults();
266 EXPECT_FALSE(r1.has_value());
271 TEST(StoreValueForwardingTests, RoutingIn)
299 auto & graph = rvsdgModule.
Rvsdg();
307 { pointerType, ioStateType, memoryStateType },
308 { bits32Type, ioStateType, memoryStateType });
312 graph.GetRootRegion(),
315 auto & q = *lambdaNode.GetFunctionArguments()[0];
316 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
317 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
323 auto & storeQ40Node =
330 auto qLoopVar = thetaNode.AddLoopVar(&q);
331 auto memLoopVar = thetaNode.AddLoopVar(&mem1);
333 auto lLoopVar = thetaNode.AddLoopVar(undefL);
336 auto & predicate = *thetaNode.predicate()->origin();
339 auto qEntryVar = gammaNode.
AddEntryVar(qLoopVar.pre);
340 auto memEntryVar = gammaNode.AddEntryVar(memLoopVar.pre);
344 *qEntryVar.branchArgument[0],
345 { memEntryVar.branchArgument[0] },
352 auto & gammaSubregion1 = *gammaNode.subregion(1);
356 auto lExitVar = gammaNode.AddExitVar({ &loadedValue, constantSeventy.output(0) });
357 auto memExitVar = gammaNode.AddExitVar({ &mem4, memEntryVar.branchArgument[1] });
360 memLoopVar.post->divert_to(memExitVar.output);
361 lLoopVar.post->divert_to(lExitVar.output);
364 lambdaNode.finalize({ lLoopVar.output, &io0, memLoopVar.output });
366 std::cout <<
rvsdg::view(&graph.GetRootRegion()) << std::endl;
371 std::cout <<
rvsdg::view(&graph.GetRootRegion()) << std::endl;
376 auto & branch0Result = *lExitVar.branchResult[0]->origin();
378 EXPECT_EQ(resultValue, 40);
382 EXPECT_EQ(&resultTraced, constantForty.output(0));
385 TEST(StoreValueForwardingTests, RouteOut)
416 auto & graph = rvsdgModule.
Rvsdg();
424 { pointerType, ioStateType, memoryStateType },
425 { bits32Type, ioStateType, memoryStateType });
429 graph.GetRootRegion(),
432 auto & q = *lambdaNode.GetFunctionArguments()[0];
433 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
434 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
440 auto & storeQ40Node =
447 auto qLoopVar = thetaNode.AddLoopVar(&q);
448 auto memLoopVar = thetaNode.AddLoopVar(&mem1);
451 auto & predicate = *thetaNode.predicate()->origin();
454 auto qEntryVar = gammaNode.
AddEntryVar(qLoopVar.pre);
455 auto memEntryVar = gammaNode.AddEntryVar(memLoopVar.pre);
458 auto & gammaSubregion0 = *gammaNode.subregion(0);
461 *qEntryVar.branchArgument[0],
462 *constantTwenty.output(0),
463 { memEntryVar.branchArgument[0] },
468 auto memExitVar = gammaNode.AddExitVar({ &mem4, memEntryVar.branchArgument[1] });
471 memLoopVar.post->divert_to(memExitVar.output);
480 lambdaNode.finalize({ &loadedValue, &io0, &mem8 });
492 const auto & resultOrigin = *lambdaNode.GetFunctionResults()[0]->origin();
493 const auto loopVar = thetaNode.MapOutputLoopVar(resultOrigin);
496 const auto & postOrigin = *loopVar.post->origin();
497 const auto exitVar = gammaNode.MapOutputExitVar(postOrigin);
499 const auto constInteger =
501 EXPECT_EQ(constInteger, 20);
505 const auto loopVar2 = thetaNode.MapPreLoopVar(traced1stRegionOrigin);
506 EXPECT_EQ(loopVar.pre, loopVar2.pre);
509 EXPECT_EQ(constInputInteger, 40);
512 TEST(StoreValueForwardingTests, RouteAroundLoadLoop)
538 auto & graph = rvsdgModule.
Rvsdg();
545 { pointerType, ioStateType, memoryStateType },
546 { bits32Type, ioStateType, memoryStateType });
550 graph.GetRootRegion(),
553 auto & q = *lambdaNode.GetFunctionArguments()[0];
554 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
555 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
559 auto & storeQ40Node =
565 auto qLoopVar = thetaNode.AddLoopVar(&q);
566 auto memLoopVar = thetaNode.AddLoopVar(&mem1);
568 auto lLoopVar = thetaNode.AddLoopVar(undefL);
570 auto & loadInLoopNode =
575 lLoopVar.post->divert_to(&l1);
576 memLoopVar.post->divert_to(&mem3);
579 auto & loadAfterLoopNode =
585 auto & addNode = rvsdg::CreateOpNode<IntegerAddOperation>({ lLoopVar.output, &l3 }, 32);
586 auto & add1 = *addNode.output(0);
589 lambdaNode.finalize({ &add1, &io0, &mem5 });
602 const auto & addLhsOrigin = *addNode.input(0)->origin();
603 const auto loopVar1 = thetaNode.MapOutputLoopVar(addLhsOrigin);
604 const auto loopVar2 = thetaNode.MapPreLoopVar(*loopVar1.post->origin());
609 const auto & addRhsOrigin = *addNode.input(1)->origin();
611 EXPECT_EQ(rvsdg::TryGetOwnerNode<rvsdg::ThetaNode>(addRhsOrigin),
nullptr);
614 TEST(StoreValueForwardingTests, RouteUninitialized)
643 auto & graph = rvsdgModule.
Rvsdg();
650 { ioStateType, memoryStateType },
651 { bits32Type, ioStateType, memoryStateType });
654 graph.GetRootRegion(),
657 auto & io0 = *lambdaNode.GetFunctionArguments()[0];
658 auto & mem0 = *lambdaNode.GetFunctionArguments()[1];
669 auto aEntryVar = gammaNode.
AddEntryVar(allocaAOutputs[0]);
670 auto memEntryVar = gammaNode.AddEntryVar(allocaAOutputs[1]);
673 auto & gammaSubregion0 = *gammaNode.subregion(0);
676 *aEntryVar.branchArgument[0],
677 *constantTwenty.output(0),
678 { memEntryVar.branchArgument[0] },
683 auto memExitVar = gammaNode.AddExitVar({ &mem3, memEntryVar.branchArgument[1] });
688 { memExitVar.output },
693 lambdaNode.finalize({ &ld, &io0, &mem0 });
699 const auto & resultOrigin = *lambdaNode.GetFunctionResults()[0]->origin();
700 EXPECT_NE(rvsdg::TryGetOwnerNode<rvsdg::GammaNode>(resultOrigin),
nullptr);
702 const auto exitVar = gammaNode.MapOutputExitVar(resultOrigin);
704 const auto [undefNode, undefOperation] =
705 rvsdg::TryGetSimpleNodeAndOptionalOp<UndefValueOperation>(*exitVar.branchResult[1]->origin());
706 EXPECT_TRUE(undefNode && undefOperation);
709 TEST(StoreValueForwardingTests, GepInLoop)
744 auto & graph = rvsdgModule.
Rvsdg();
752 { ioStateType, memoryStateType },
753 { bits32Type, ioStateType, memoryStateType });
756 graph.GetRootRegion(),
759 auto & io0 = *lambdaNode.GetFunctionArguments()[0];
760 auto & mem0 = *lambdaNode.GetFunctionArguments()[1];
775 { constantZero.output(0), constantTwo.output(0) },
779 { constantZero.output(0), constantThree.output(0) },
785 *constantTwenty.output(0),
786 { allocaAOutputs[1] },
789 auto & storeA330Node =
795 auto aLoopVar = thetaNode.AddLoopVar(allocaAOutputs[0]);
796 auto a2LoopVar = thetaNode.AddLoopVar(a2);
797 auto memLoopVar = thetaNode.AddLoopVar(&mem2);
800 auto & loadInLoopNode =
812 auto & addLoadedOneNode =
813 rvsdg::CreateOpNode<IntegerAddOperation>({ &loadedValue, constantOneInLoop.output(0) }, 32);
814 auto & incrementedValue = *addLoadedOneNode.output(0);
824 memLoopVar.post->divert_to(&mem5);
827 auto & loadAfterLoopA2Node =
833 auto & addResultNode = rvsdg::CreateOpNode<IntegerAddOperation>({ &loadedA2, &loadedA3 }, 32);
834 auto & resultValue = *addResultNode.output(0);
836 lambdaNode.finalize({ &resultValue, &io0, &mem0 });
838 std::cout <<
rvsdg::view(&graph.GetRootRegion()) << std::endl;
843 std::cout <<
rvsdg::view(&graph.GetRootRegion()) << std::endl;
849 const auto & loadedInLoopOrigin = *addLoadedOneNode.input(0)->origin();
850 const auto loadedLoopVar = thetaNode.MapPreLoopVar(loadedInLoopOrigin);
852 EXPECT_EQ(loadedLoopVar.post->origin(), addLoadedOneNode.output(0));
855 const auto & addLhsOrigin = *addResultNode.input(0)->origin();
856 const auto a2ResultLoopVar = thetaNode.MapOutputLoopVar(addLhsOrigin);
857 EXPECT_EQ(a2ResultLoopVar.post->origin(), addLoadedOneNode.output(0));
861 const auto & addRhsOrigin = *addResultNode.input(1)->origin();
862 EXPECT_EQ(&addRhsOrigin, constantThirty.output(0));
static jlm::util::StatisticsCollector statisticsCollector
TEST(StoreValueForwardingTests, NestedAllocas)
static void RunStoreValueForwarding(jlm::llvm::LlvmRvsdgModule &rvsdgModule)
static std::vector< rvsdg::Output * > create(std::shared_ptr< const rvsdg::Type > allocatedType, rvsdg::Output *count, const size_t alignment)
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 std::shared_ptr< const IOStateType > Create()
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 rvsdg::SimpleNode & CreateNode(rvsdg::Region ®ion, std::unique_ptr< LoadNonVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
static rvsdg::Output & LoadedValueOutput(const rvsdg::Node &node)
static rvsdg::Node::OutputIteratorRange MemoryStateOutputs(const rvsdg::Node &node) noexcept
static std::shared_ptr< const MemoryStateType > Create()
static std::shared_ptr< const PointerType > Create()
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
static rvsdg::Node::OutputIteratorRange MemoryStateOutputs(const rvsdg::Node &node) noexcept
Store Value Forwarding Optimization.
void Run(rvsdg::RvsdgModule &module, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
static jlm::rvsdg::Output * Create(rvsdg::Region ®ion, std::shared_ptr< const jlm::rvsdg::Type > type)
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
static Output & create(Region ®ion, ControlValueRepresentation value)
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 numAlternatives, std::vector< std::shared_ptr< const Type >> matchContentTypes)
EntryVar AddEntryVar(rvsdg::Output *origin)
Routes a variable into the gamma branches.
Region & GetRootRegion() const noexcept
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
static ThetaNode * create(rvsdg::Region *parent)
static std::shared_ptr< const UnitType > Create()
Global memory state passed between functions.
rvsdg::Output & traceOutput(rvsdg::Output &output, const rvsdg::Region *withinRegion)
std::optional< int64_t > tryGetConstantSignedInteger(const rvsdg::Output &output)
static bool ThetaLoopVarIsInvariant(const ThetaNode::LoopVar &loopVar) noexcept
std::string view(const rvsdg::Region *region)