Jlm
Loading...
Searching...
No Matches
DeadNodeEliminationTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2017 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
17#include <jlm/rvsdg/control.hpp>
18#include <jlm/rvsdg/gamma.hpp>
19#include <jlm/rvsdg/Phi.hpp>
22#include <jlm/rvsdg/theta.hpp>
23#include <jlm/rvsdg/view.hpp>
25
26static void
33
34TEST(DeadNodeEliminationTests, RootRegion)
35{
36 using namespace jlm::llvm;
37
38 // Arrange
39 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
40 auto & graph = rvsdgModule.Rvsdg();
41
44
46 jlm::rvsdg::view(graph, stdout);
47
48 // Act
49 RunDeadNodeElimination(rvsdgModule);
50 jlm::rvsdg::view(graph, stdout);
51
52 // Assert
53 EXPECT_EQ(graph.GetRootRegion().narguments(), 1u);
54}
55
56TEST(DeadNodeEliminationTests, Gamma1)
57{
58 using namespace jlm::llvm;
59
60 // Arrange
62 auto controlType = jlm::rvsdg::ControlType::Create(2);
63
64 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
65 auto & graph = rvsdgModule.Rvsdg();
66 auto c = &jlm::rvsdg::GraphImport::Create(graph, controlType, "c");
67 auto x = &jlm::rvsdg::GraphImport::Create(graph, valueType, "x");
68 auto y = &jlm::rvsdg::GraphImport::Create(graph, valueType, "y");
69
70 auto gamma = jlm::rvsdg::GammaNode::create(c, 2);
71 auto ev1 = gamma->AddEntryVar(x);
72 auto ev2 = gamma->AddEntryVar(y);
73 auto ev3 = gamma->AddEntryVar(x);
74
76 gamma->subregion(1),
77 { ev2.branchArgument[1] },
78 { valueType })
79 ->output(0);
80
81 gamma->AddExitVar(ev1.branchArgument);
82 gamma->AddExitVar({ ev2.branchArgument[0], t });
83 gamma->AddExitVar({ ev3.branchArgument[0], ev1.branchArgument[1] });
84
85 jlm::rvsdg::GraphExport::Create(*gamma->output(0), "z");
86 jlm::rvsdg::GraphExport::Create(*gamma->output(2), "w");
87 jlm::rvsdg::view(graph, stdout);
88
89 // Act
90 RunDeadNodeElimination(rvsdgModule);
91 jlm::rvsdg::view(graph, stdout);
92
93 // Assert
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);
99}
100
101TEST(DeadNodeEliminationTests, Gamma2)
102{
103 using namespace jlm::llvm;
104 using namespace jlm::rvsdg;
105
106 // Arrange
107 auto valueType = jlm::rvsdg::TestType::createValueType();
108 auto controlType = jlm::rvsdg::ControlType::Create(2);
109
110 jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
111 auto & graph = rvsdgModule.Rvsdg();
112 auto c = &jlm::rvsdg::GraphImport::Create(graph, controlType, "c");
113 auto x = &jlm::rvsdg::GraphImport::Create(graph, valueType, "x");
114
115 auto gamma = jlm::rvsdg::GammaNode::create(c, 2);
116 gamma->AddEntryVar(x);
117
118 auto n1 = TestOperation::createNode(gamma->subregion(0), {}, { valueType })->output(0);
119 auto n2 = TestOperation::createNode(gamma->subregion(1), {}, { valueType })->output(0);
120
121 gamma->AddExitVar({ n1, n2 });
122
123 jlm::rvsdg::GraphExport::Create(*gamma->output(0), "x");
124 jlm::rvsdg::view(graph, stdout);
125
126 // Act
127 RunDeadNodeElimination(rvsdgModule);
128 jlm::rvsdg::view(graph, stdout);
129
130 // Assert
131 EXPECT_EQ(graph.GetRootRegion().narguments(), 1u);
132}
133
134TEST(DeadNodeEliminationTests, Theta)
135{
136 using namespace jlm::llvm;
137 using namespace jlm::rvsdg;
138
139 // Arrange
140 auto valueType = jlm::rvsdg::TestType::createValueType();
141 auto controlType = jlm::rvsdg::ControlType::Create(2);
142
143 jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
144 auto & graph = rvsdgModule.Rvsdg();
145 auto x = &jlm::rvsdg::GraphImport::Create(graph, valueType, "x");
146 auto y = &jlm::rvsdg::GraphImport::Create(graph, valueType, "y");
147 auto z = &jlm::rvsdg::GraphImport::Create(graph, valueType, "z");
148
149 auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
150
151 auto lv1 = theta->AddLoopVar(x);
152 auto lv2 = theta->AddLoopVar(y);
153 auto lv3 = theta->AddLoopVar(z);
154 auto lv4 = theta->AddLoopVar(y);
155
156 lv1.post->divert_to(lv2.pre);
157 lv2.post->divert_to(lv1.pre);
158
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);
162
163 auto c = TestOperation::createNode(theta->subregion(), {}, { controlType })->output(0);
164 theta->set_predicate(c);
165
166 jlm::rvsdg::GraphExport::Create(*lv1.output, "a");
167 jlm::rvsdg::GraphExport::Create(*lv4.output, "b");
168 jlm::rvsdg::view(graph, stdout);
169
170 // Act
171 RunDeadNodeElimination(rvsdgModule);
172 jlm::rvsdg::view(graph, stdout);
173
174 // Assert
175 EXPECT_EQ(theta->noutputs(), 3u);
176 EXPECT_EQ(theta->subregion()->numNodes(), 1u);
177 EXPECT_EQ(graph.GetRootRegion().narguments(), 2u);
178}
179
180TEST(DeadNodeEliminationTests, NestedTheta)
181{
182 using namespace jlm::llvm;
183
184 // Arrange
185 auto valueType = jlm::rvsdg::TestType::createValueType();
186 auto controlType = jlm::rvsdg::ControlType::Create(2);
187
188 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
189 auto & graph = rvsdgModule.Rvsdg();
190 auto c = &jlm::rvsdg::GraphImport::Create(graph, controlType, "c");
191 auto x = &jlm::rvsdg::GraphImport::Create(graph, valueType, "x");
192 auto y = &jlm::rvsdg::GraphImport::Create(graph, valueType, "y");
193
194 auto outerTheta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
195
196 auto lvo1 = outerTheta->AddLoopVar(c);
197 auto lvo2 = outerTheta->AddLoopVar(x);
198 auto lvo3 = outerTheta->AddLoopVar(y);
199
200 auto innerTheta = jlm::rvsdg::ThetaNode::create(outerTheta->subregion());
201
202 auto lvi1 = innerTheta->AddLoopVar(lvo1.pre);
203 auto lvi2 = innerTheta->AddLoopVar(lvo2.pre);
204 auto lvi3 = innerTheta->AddLoopVar(lvo3.pre);
205
206 lvi2.post->divert_to(lvi3.pre);
207
208 innerTheta->set_predicate(lvi1.pre);
209
210 lvo2.post->divert_to(lvi2.output);
211 lvo3.post->divert_to(lvi2.output);
212
213 outerTheta->set_predicate(lvo1.pre);
214
215 jlm::rvsdg::GraphExport::Create(*lvo3.output, "y");
216 jlm::rvsdg::view(graph, stdout);
217
218 // Act
219 RunDeadNodeElimination(rvsdgModule);
220 jlm::rvsdg::view(graph, stdout);
221
222 // Assert
223 EXPECT_EQ(outerTheta->noutputs(), 3u);
224}
225
226TEST(DeadNodeEliminationTests, EvolvingTheta)
227{
228 using namespace jlm::llvm;
229
230 // Arrange
231 auto valueType = jlm::rvsdg::TestType::createValueType();
232 auto controlType = jlm::rvsdg::ControlType::Create(2);
233
234 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
235 auto & graph = rvsdgModule.Rvsdg();
236 auto c = &jlm::rvsdg::GraphImport::Create(graph, controlType, "c");
237 auto x1 = &jlm::rvsdg::GraphImport::Create(graph, valueType, "x1");
238 auto x2 = &jlm::rvsdg::GraphImport::Create(graph, valueType, "x2");
239 auto x3 = &jlm::rvsdg::GraphImport::Create(graph, valueType, "x3");
240 auto x4 = &jlm::rvsdg::GraphImport::Create(graph, valueType, "x4");
241
242 auto theta = jlm::rvsdg::ThetaNode::create(&graph.GetRootRegion());
243
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);
249
250 lv1.post->divert_to(lv2.pre);
251 lv2.post->divert_to(lv3.pre);
252 lv3.post->divert_to(lv4.pre);
253
254 theta->set_predicate(lv0.pre);
255
256 jlm::rvsdg::GraphExport::Create(*lv1.output, "x1");
257 jlm::rvsdg::view(graph, stdout);
258
259 // Act
260 RunDeadNodeElimination(rvsdgModule);
261 jlm::rvsdg::view(graph, stdout);
262
263 // Assert
264 EXPECT_EQ(theta->noutputs(), 5u);
265}
266
267TEST(DeadNodeEliminationTests, Lambda)
268{
269 using namespace jlm::llvm;
270 using namespace jlm::rvsdg;
271
272 // Arrange
273 auto valueType = jlm::rvsdg::TestType::createValueType();
274
275 jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
276 auto & graph = rvsdgModule.Rvsdg();
277 auto x = &jlm::rvsdg::GraphImport::Create(graph, valueType, "x");
278 auto y = &jlm::rvsdg::GraphImport::Create(graph, valueType, "y");
279
280 auto lambda = jlm::rvsdg::LambdaNode::Create(
281 graph.GetRootRegion(),
282 LlvmLambdaOperation::Create(
283 jlm::rvsdg::FunctionType::Create({ valueType }, { valueType, valueType }),
284 "f",
285 Linkage::externalLinkage));
286
287 auto cv1 = lambda->AddContextVar(*x).inner;
288 auto cv2 = lambda->AddContextVar(*y).inner;
289 TestOperation::createNode(
290 lambda->subregion(),
291 { lambda->GetFunctionArguments()[0], cv1 },
292 { valueType });
293
294 auto output = lambda->finalize({ lambda->GetFunctionArguments()[0], cv2 });
295
297 jlm::rvsdg::view(graph, stdout);
298
299 // Act
300 RunDeadNodeElimination(rvsdgModule);
301 jlm::rvsdg::view(graph, stdout);
302
303 // Assert
304 EXPECT_EQ(lambda->subregion()->numNodes(), 0u);
305 EXPECT_EQ(graph.GetRootRegion().narguments(), 1u);
306}
307
308TEST(DeadNodeEliminationTests, Phi)
309{
310 using namespace jlm::llvm;
311 using namespace jlm::rvsdg;
312
313 // Arrange
314 auto valueType = TestType::createValueType();
315 auto functionType = FunctionType::Create({ valueType }, { valueType });
316
317 jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
318 auto & rvsdg = rvsdgModule.Rvsdg();
319 auto x = &jlm::rvsdg::GraphImport::Create(rvsdg, valueType, "x");
320 auto y = &jlm::rvsdg::GraphImport::Create(rvsdg, valueType, "y");
321 auto z = &jlm::rvsdg::GraphImport::Create(rvsdg, valueType, "z");
322
323 auto setupF1 = [&](Region & region, Output & rv2, Output & dx)
324 {
325 auto lambda1 = jlm::rvsdg::LambdaNode::Create(
326 region,
327 LlvmLambdaOperation::Create(functionType, "f1", Linkage::externalLinkage));
328 auto f2Argument = lambda1->AddContextVar(rv2).inner;
329 auto xArgument = lambda1->AddContextVar(dx).inner;
330
331 auto result =
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 })
336 .output(0);
337
338 return lambda1->finalize({ result });
339 };
340
341 auto setupF2 = [&](Region & region, Output & rv1, Output & dy)
342 {
343 auto lambda2 = jlm::rvsdg::LambdaNode::Create(
344 region,
345 LlvmLambdaOperation::Create(functionType, "f2", Linkage::externalLinkage));
346 auto f1Argument = lambda2->AddContextVar(rv1).inner;
347 lambda2->AddContextVar(dy);
348
350 { lambda2->GetFunctionArguments()[0], f1Argument },
351 std::vector<std::shared_ptr<const Type>>{ valueType, functionType },
352 std::vector<std::shared_ptr<const Type>>{ valueType })
353 .output(0);
354
355 return lambda2->finalize({ result });
356 };
357
358 auto setupF3 = [&](Region & region, Output & dz)
359 {
360 auto lambda3 = jlm::rvsdg::LambdaNode::Create(
361 region,
362 LlvmLambdaOperation::Create(functionType, "f3", Linkage::externalLinkage));
363 auto zArgument = lambda3->AddContextVar(dz).inner;
364
366 { lambda3->GetFunctionArguments()[0], zArgument },
367 std::vector<std::shared_ptr<const Type>>{ valueType, valueType },
368 std::vector<std::shared_ptr<const Type>>{ valueType })
369 .output(0);
370
371 return lambda3->finalize({ result });
372 };
373
374 auto setupF4 = [&](Region & region)
375 {
376 auto lambda = jlm::rvsdg::LambdaNode::Create(
377 region,
378 LlvmLambdaOperation::Create(functionType, "f4", Linkage::externalLinkage));
379 return lambda->finalize({ lambda->GetFunctionArguments()[0] });
380 };
381
382 PhiBuilder phiBuilder;
383 phiBuilder.begin(&rvsdg.GetRootRegion());
384 auto & phiSubregion = *phiBuilder.subregion();
385
386 auto rv1 = phiBuilder.AddFixVar(functionType);
387 auto rv2 = phiBuilder.AddFixVar(functionType);
388 auto rv3 = phiBuilder.AddFixVar(functionType);
389 auto rv4 = phiBuilder.AddFixVar(functionType);
390 auto dx = phiBuilder.AddContextVar(*x);
391 auto dy = phiBuilder.AddContextVar(*y);
392 auto dz = phiBuilder.AddContextVar(*z);
393
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);
398
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();
404
405 jlm::rvsdg::GraphExport::Create(*phiNode->output(0), "f1");
406 jlm::rvsdg::GraphExport::Create(*phiNode->output(3), "f4");
407 view(rvsdg, stdout);
408
409 // Act
410 RunDeadNodeElimination(rvsdgModule);
411 view(rvsdg, stdout);
412
413 // Assert
414 EXPECT_EQ(phiNode->noutputs(), 3u); // f1, f2, and f4 are alive
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); // f1, f2, and f4 are alive
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); // f1, f2, f4, and dx are alive
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); // dx is alive
428 EXPECT_EQ(phiNode->input(0), dx.input);
429}
430
431TEST(DeadNodeEliminationTests, Delta)
432{
433 using namespace jlm::llvm;
434 using namespace jlm::rvsdg;
435
436 // Arrange
437 auto valueType = TestType::createValueType();
438
439 jlm::llvm::LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
440 auto & rvsdg = rvsdgModule.Rvsdg();
441
442 auto x = &jlm::rvsdg::GraphImport::Create(rvsdg, valueType, "x");
443 auto y = &jlm::rvsdg::GraphImport::Create(rvsdg, valueType, "y");
444 auto z = &jlm::rvsdg::GraphImport::Create(rvsdg, valueType, "z");
445
446 auto deltaNode = jlm::rvsdg::DeltaNode::Create(
447 &rvsdg.GetRootRegion(),
448 LlvmDeltaOperation::Create(valueType, "delta", Linkage::externalLinkage, "", false, 4));
449
450 auto xArgument = deltaNode->AddContextVar(*x).inner;
451 deltaNode->AddContextVar(*y);
452 auto zArgument = deltaNode->AddContextVar(*z).inner;
453
455 { xArgument },
456 std::vector<std::shared_ptr<const Type>>{ valueType },
457 std::vector<std::shared_ptr<const Type>>{ valueType })
458 .output(0);
459
461 { zArgument },
462 std::vector<std::shared_ptr<const Type>>{ valueType },
463 std::vector<std::shared_ptr<const Type>>{ valueType });
464
465 auto deltaOutput = &deltaNode->finalize(result);
466 jlm::rvsdg::GraphExport::Create(*deltaOutput, "");
467 view(rvsdg, stdout);
468
469 // Act
470 RunDeadNodeElimination(rvsdgModule);
471 view(rvsdg, stdout);
472
473 // Assert
474 EXPECT_EQ(deltaNode->subregion()->numNodes(), 1u);
475 EXPECT_EQ(deltaNode->ninputs(), 1u);
476}
477
478TEST(DeadNodeEliminationTests, LoadNodes)
479{
480 using namespace jlm::llvm;
481 using namespace jlm::rvsdg;
482
483 // Arrange
484 const auto pointerType = PointerType::Create();
485 const auto memoryStateType = MemoryStateType::Create();
486 const auto valueType = TestType::createValueType();
487
488 LlvmRvsdgModule rvsdgModule(jlm::util::FilePath(""), "", "");
489 auto & rvsdg = rvsdgModule.Rvsdg();
490
491 auto lambdaNode = LambdaNode::Create(
492 rvsdg.GetRootRegion(),
493 LlvmLambdaOperation::Create(
494 FunctionType::Create({ pointerType, memoryStateType }, { memoryStateType }),
495 "f",
496 Linkage::externalLinkage));
497 auto addressArgument = lambdaNode->GetFunctionArguments()[0];
498 auto memoryStateArgument = lambdaNode->GetFunctionArguments()[1];
499
500 auto & oneNode = IntegerConstantOperation::Create(*lambdaNode->subregion(), 32, 1);
501 auto allocaResults = AllocaOperation::create(pointerType, oneNode.output(0), 4);
502
503 auto & storeNode = StoreNonVolatileOperation::CreateNode(
504 *allocaResults[0],
505 *addressArgument,
506 { allocaResults[1] },
507 4);
508
509 auto & allocaLoadNode = LoadNonVolatileOperation::CreateNode(
510 *allocaResults[0],
511 { storeNode.output(0) },
512 pointerType,
513 4);
514
515 auto & loadNode = LoadNonVolatileOperation::CreateNode(
516 *allocaLoadNode.output(0),
517 { memoryStateArgument },
518 valueType,
519 4);
520
521 auto & lambdaExitMergeNode = LambdaExitMemoryStateMergeOperation::CreateNode(
522 *lambdaNode->subregion(),
523 { allocaLoadNode.output(1), loadNode.output(1) },
524 { 0, 1 });
525
526 auto lambdaOutput = lambdaNode->finalize({ lambdaExitMergeNode.output(0) });
527 GraphExport::Create(*lambdaOutput, "f");
528
529 view(rvsdg, stdout);
530
531 // Act
532 RunDeadNodeElimination(rvsdgModule);
533 view(rvsdg, stdout);
534
535 // Assert
536 // We expect that both load nodes have been removed.
537 EXPECT_FALSE(
538 Region::containsOperation<LoadNonVolatileOperation>(*lambdaNode->subregion(), false));
539 EXPECT_EQ(lambdaNode->subregion()->numNodes(), 4u);
540}
static jlm::util::StatisticsCollector statisticsCollector
Dead Node Elimination Optimization.
void Run(rvsdg::RvsdgModule &module, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
static std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
Definition control.cpp:50
static DeltaNode * Create(rvsdg::Region *parent, std::unique_ptr< DeltaOperation > op)
Definition delta.hpp:313
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)
Definition gamma.hpp:161
static GraphExport & Create(Output &origin, std::string name)
Definition graph.cpp:62
static GraphImport & Create(Graph &graph, std::shared_ptr< const rvsdg::Type > type, std::string name)
Definition graph.cpp:36
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
Definition lambda.cpp:141
PhiNode * end()
Definition Phi.cpp:270
PhiNode::ContextVar AddContextVar(jlm::rvsdg::Output &origin)
Definition Phi.cpp:251
PhiNode::FixVar AddFixVar(std::shared_ptr< const jlm::rvsdg::Type > type)
Definition Phi.cpp:257
void begin(rvsdg::Region *parent)
Definition Phi.hpp:355
rvsdg::Region * subregion() const noexcept
Definition Phi.hpp:349
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
Graph & Rvsdg() noexcept
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()
Definition TestType.cpp:67
static ThetaNode * create(rvsdg::Region *parent)
Definition theta.hpp:73
TEST(DeadNodeEliminationTests, TestDeadLoopNode)
static void RunDeadNodeElimination(jlm::llvm::LlvmRvsdgModule &rvsdgModule)
Global memory state passed between functions.
std::string view(const rvsdg::Region *region)
Definition view.cpp:142
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872