6 #include <gtest/gtest.h>
34 TEST(DeadNodeEliminationTests, RootRegion)
40 auto & graph = rvsdgModule.
Rvsdg();
53 EXPECT_EQ(graph.GetRootRegion().narguments(), 1u);
56 TEST(DeadNodeEliminationTests, Gamma1)
65 auto & graph = rvsdgModule.
Rvsdg();
71 auto ev1 = gamma->AddEntryVar(x);
72 auto ev2 = gamma->AddEntryVar(y);
73 auto ev3 = gamma->AddEntryVar(x);
77 { ev2.branchArgument[1] },
81 gamma->AddExitVar(ev1.branchArgument);
82 gamma->AddExitVar({ ev2.branchArgument[0], t });
83 gamma->AddExitVar({ ev3.branchArgument[0], ev1.branchArgument[1] });
94 EXPECT_EQ(gamma->noutputs(), 2u);
95 EXPECT_EQ(gamma->subregion(1)->numNodes(), 0u);
96 EXPECT_EQ(gamma->subregion(1)->narguments(), 3u);
97 EXPECT_EQ(gamma->ninputs(), 3u);
98 EXPECT_EQ(graph.GetRootRegion().narguments(), 2u);
101 TEST(DeadNodeEliminationTests, Gamma2)
111 auto & graph = rvsdgModule.
Rvsdg();
116 gamma->AddEntryVar(x);
118 auto n1 = TestOperation::createNode(gamma->subregion(0), {}, { valueType })->output(0);
119 auto n2 = TestOperation::createNode(gamma->subregion(1), {}, { valueType })->output(0);
121 gamma->AddExitVar({ n1, n2 });
131 EXPECT_EQ(graph.GetRootRegion().narguments(), 1u);
134 TEST(DeadNodeEliminationTests, Theta)
144 auto & graph = rvsdgModule.
Rvsdg();
151 auto lv1 = theta->AddLoopVar(x);
152 auto lv2 = theta->AddLoopVar(y);
153 auto lv3 = theta->AddLoopVar(z);
154 auto lv4 = theta->AddLoopVar(y);
156 lv1.post->divert_to(lv2.pre);
157 lv2.post->divert_to(lv1.pre);
159 auto t = TestOperation::createNode(theta->subregion(), { lv3.pre }, { valueType })->output(0);
160 lv3.post->divert_to(t);
161 lv4.post->divert_to(lv2.pre);
163 auto c = TestOperation::createNode(theta->subregion(), {}, { controlType })->output(0);
164 theta->set_predicate(c);
175 EXPECT_EQ(theta->noutputs(), 3u);
176 EXPECT_EQ(theta->subregion()->numNodes(), 1u);
177 EXPECT_EQ(graph.GetRootRegion().narguments(), 2u);
180 TEST(DeadNodeEliminationTests, NestedTheta)
189 auto & graph = rvsdgModule.
Rvsdg();
196 auto lvo1 = outerTheta->AddLoopVar(c);
197 auto lvo2 = outerTheta->AddLoopVar(x);
198 auto lvo3 = outerTheta->AddLoopVar(y);
202 auto lvi1 = innerTheta->AddLoopVar(lvo1.pre);
203 auto lvi2 = innerTheta->AddLoopVar(lvo2.pre);
204 auto lvi3 = innerTheta->AddLoopVar(lvo3.pre);
206 lvi2.post->divert_to(lvi3.pre);
208 innerTheta->set_predicate(lvi1.pre);
210 lvo2.post->divert_to(lvi2.output);
211 lvo3.post->divert_to(lvi2.output);
213 outerTheta->set_predicate(lvo1.pre);
223 EXPECT_EQ(outerTheta->noutputs(), 3u);
226 TEST(DeadNodeEliminationTests, EvolvingTheta)
235 auto & graph = rvsdgModule.
Rvsdg();
244 auto lv0 = theta->AddLoopVar(c);
245 auto lv1 = theta->AddLoopVar(x1);
246 auto lv2 = theta->AddLoopVar(x2);
247 auto lv3 = theta->AddLoopVar(x3);
248 auto lv4 = theta->AddLoopVar(x4);
250 lv1.post->divert_to(lv2.pre);
251 lv2.post->divert_to(lv3.pre);
252 lv3.post->divert_to(lv4.pre);
254 theta->set_predicate(lv0.pre);
264 EXPECT_EQ(theta->noutputs(), 5u);
267 TEST(DeadNodeEliminationTests, Lambda)
276 auto & graph = rvsdgModule.
Rvsdg();
281 graph.GetRootRegion(),
287 auto cv1 = lambda->AddContextVar(*x).inner;
288 auto cv2 = lambda->AddContextVar(*y).inner;
289 TestOperation::createNode(
291 { lambda->GetFunctionArguments()[0], cv1 },
294 auto output = lambda->finalize({ lambda->GetFunctionArguments()[0], cv2 });
304 EXPECT_EQ(lambda->subregion()->numNodes(), 0u);
305 EXPECT_EQ(graph.GetRootRegion().narguments(), 1u);
308 TEST(DeadNodeEliminationTests, Phi)
314 auto valueType = TestType::createValueType();
315 auto functionType = FunctionType::Create({ valueType }, { valueType });
318 auto & rvsdg = rvsdgModule.Rvsdg();
328 auto f2Argument = lambda1->AddContextVar(rv2).inner;
329 auto xArgument = lambda1->AddContextVar(dx).inner;
332 jlm::rvsdg::CreateOpNode<TestOperation>(
333 { lambda1->GetFunctionArguments()[0], f2Argument, xArgument },
334 std::vector<std::shared_ptr<const Type>>{ valueType, functionType, valueType },
335 std::vector<std::shared_ptr<const Type>>{ valueType })
338 return lambda1->finalize({ result });
346 auto f1Argument = lambda2->AddContextVar(rv1).inner;
347 lambda2->AddContextVar(dy);
349 auto result = jlm::rvsdg::CreateOpNode<TestOperation>(
350 { lambda2->GetFunctionArguments()[0], f1Argument },
351 std::vector<std::shared_ptr<const Type>>{ valueType, functionType },
352 std::vector<std::shared_ptr<const Type>>{ valueType })
355 return lambda2->finalize({ result });
363 auto zArgument = lambda3->AddContextVar(dz).inner;
365 auto result = jlm::rvsdg::CreateOpNode<TestOperation>(
366 { lambda3->GetFunctionArguments()[0], zArgument },
367 std::vector<std::shared_ptr<const Type>>{ valueType, valueType },
368 std::vector<std::shared_ptr<const Type>>{ valueType })
371 return lambda3->finalize({ result });
374 auto setupF4 = [&](
Region & region)
379 return lambda->finalize({ lambda->GetFunctionArguments()[0] });
383 phiBuilder.
begin(&rvsdg.GetRootRegion());
384 auto & phiSubregion = *phiBuilder.
subregion();
386 auto rv1 = phiBuilder.
AddFixVar(functionType);
387 auto rv2 = phiBuilder.
AddFixVar(functionType);
388 auto rv3 = phiBuilder.
AddFixVar(functionType);
389 auto rv4 = phiBuilder.
AddFixVar(functionType);
394 auto f1 = setupF1(phiSubregion, *rv2.recref, *dx.inner);
395 auto f2 = setupF2(phiSubregion, *rv1.recref, *dy.inner);
396 auto f3 = setupF3(phiSubregion, *dz.inner);
397 auto f4 = setupF4(phiSubregion);
399 rv1.result->divert_to(f1);
400 rv2.result->divert_to(f2);
401 rv3.result->divert_to(f3);
402 rv4.result->divert_to(f4);
403 auto phiNode = phiBuilder.
end();
414 EXPECT_EQ(phiNode->noutputs(), 3u);
415 EXPECT_EQ(phiNode->output(0), rv1.output);
416 EXPECT_EQ(phiNode->output(1), rv2.output);
417 EXPECT_EQ(phiNode->output(2), rv4.output);
418 EXPECT_EQ(phiSubregion.nresults(), 3u);
419 EXPECT_EQ(phiSubregion.result(0), rv1.result);
420 EXPECT_EQ(phiSubregion.result(1), rv2.result);
421 EXPECT_EQ(phiSubregion.result(2), rv4.result);
422 EXPECT_EQ(phiSubregion.narguments(), 4u);
423 EXPECT_EQ(phiSubregion.argument(0), rv1.recref);
424 EXPECT_EQ(phiSubregion.argument(1), rv2.recref);
425 EXPECT_EQ(phiSubregion.argument(2), rv4.recref);
426 EXPECT_EQ(phiSubregion.argument(3), dx.inner);
427 EXPECT_EQ(phiNode->ninputs(), 1u);
428 EXPECT_EQ(phiNode->input(0), dx.input);
431 TEST(DeadNodeEliminationTests, Delta)
437 auto valueType = TestType::createValueType();
440 auto & rvsdg = rvsdgModule.
Rvsdg();
447 &rvsdg.GetRootRegion(),
456 auto xArgument = deltaNode->AddContextVar(*x).inner;
457 deltaNode->AddContextVar(*y);
458 auto zArgument = deltaNode->AddContextVar(*z).inner;
460 auto result = jlm::rvsdg::CreateOpNode<TestOperation>(
462 std::vector<std::shared_ptr<const Type>>{ valueType },
463 std::vector<std::shared_ptr<const Type>>{ valueType })
466 jlm::rvsdg::CreateOpNode<TestOperation>(
468 std::vector<std::shared_ptr<const Type>>{ valueType },
469 std::vector<std::shared_ptr<const Type>>{ valueType });
471 auto deltaOutput = &deltaNode->finalize(result);
480 EXPECT_EQ(deltaNode->subregion()->numNodes(), 1u);
481 EXPECT_EQ(deltaNode->ninputs(), 1u);
484 TEST(DeadNodeEliminationTests, LoadNodes)
492 const auto valueType = TestType::createValueType();
495 auto & rvsdg = rvsdgModule.
Rvsdg();
497 auto lambdaNode = LambdaNode::Create(
498 rvsdg.GetRootRegion(),
500 FunctionType::Create({ pointerType, memoryStateType }, { memoryStateType }),
503 auto addressArgument = lambdaNode->GetFunctionArguments()[0];
504 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[1];
512 { allocaResults[1] },
517 { storeNode.output(0) },
522 *allocaLoadNode.output(0),
523 { memoryStateArgument },
528 *lambdaNode->subregion(),
529 { allocaLoadNode.output(1), loadNode.output(1) },
532 auto lambdaOutput = lambdaNode->finalize({ lambdaExitMergeNode.output(0) });
533 GraphExport::Create(*lambdaOutput,
"f");
544 Region::ContainsOperation<LoadNonVolatileOperation>(*lambdaNode->subregion(),
false));
545 EXPECT_EQ(lambdaNode->subregion()->numNodes(), 4u);
static jlm::util::StatisticsCollector statisticsCollector
static std::vector< rvsdg::Output * > create(std::shared_ptr< const rvsdg::Type > allocatedType, rvsdg::Output *count, const size_t alignment)
Dead Node Elimination Optimization.
void Run(rvsdg::RvsdgModule &module, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
static std::unique_ptr< DeltaOperation > Create(std::shared_ptr< const rvsdg::Type > type, const std::string &name, const Linkage &linkage, std::string section, bool constant, const size_t alignment)
static rvsdg::Node & Create(rvsdg::Region ®ion, IntegerValueRepresentation representation)
static rvsdg::SimpleNode & CreateNode(rvsdg::Region ®ion, const std::vector< rvsdg::Output * > &operands, const std::vector< MemoryNodeId > &memoryNodeIds)
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 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 std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
static DeltaNode * Create(rvsdg::Region *parent, std::unique_ptr< DeltaOperation > op)
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)
rvsdg::Region * subregion() const noexcept
PhiNode::ContextVar AddContextVar(jlm::rvsdg::Output &origin)
PhiNode::FixVar AddFixVar(std::shared_ptr< const jlm::rvsdg::Type > type)
void begin(rvsdg::Region *parent)
Represent acyclic RVSDG subgraphs.
NodeOutput * output(size_t index) const noexcept
static SimpleNode * createNode(Region *region, const std::vector< Output * > &operands, std::vector< std::shared_ptr< const Type >> resultTypes)
static std::shared_ptr< const TestType > createValueType()
static ThetaNode * create(rvsdg::Region *parent)
TEST(DeadNodeEliminationTests, TestDeadLoopNode)
static void RunDeadNodeElimination(jlm::llvm::LlvmRvsdgModule &rvsdgModule)
Global memory state passed between functions.
std::string view(const rvsdg::Region *region)