41TEST(StoreValueForwardingTests, NestedAllocas)
63 auto & graph = rvsdgModule.
Rvsdg();
64 const auto pointerType = PointerType::Create();
65 const auto intType = rvsdg::BitType::Create(32);
66 const auto ioStateType = IOStateType::Create();
67 const auto memoryStateType = MemoryStateType::Create();
69 const auto funcType = rvsdg::FunctionType::Create(
70 { ioStateType, memoryStateType },
71 { intType, ioStateType, memoryStateType });
74 auto & lambdaNode = *rvsdg::LambdaNode::Create(
75 graph.GetRootRegion(),
76 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
78 const auto io0 = lambdaNode.GetFunctionArguments()[0];
79 const auto mem0 = lambdaNode.GetFunctionArguments()[1];
81 auto & constantOne = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 1);
82 auto allocaPOutputs = AllocaOperation::create(intType, constantOne.output(0), 4);
83 auto allocaAOutputs = AllocaOperation::create(intType, constantOne.output(0), 4);
86 auto & constantTwenty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 20);
89 auto & storePANode = StoreNonVolatileOperation::CreateNode(
92 { allocaPOutputs[1], allocaAOutputs[1] },
96 auto & storeA20Node = StoreNonVolatileOperation::CreateNode(
98 *constantTwenty.output(0),
99 { storePANode.output(0), storePANode.output(1) },
103 auto & loadPNode = LoadNonVolatileOperation::CreateNode(
105 { storeA20Node.output(0), storeA20Node.output(1) },
110 auto & loadA0Node = LoadNonVolatileOperation::CreateNode(
111 *loadPNode.output(0),
112 { loadPNode.output(1), loadPNode.output(2) },
116 lambdaNode.finalize({ loadA0Node.output(0), io0, mem0 });
128 size_t allocaCount = 0;
129 size_t storeCount = 0;
130 size_t loadCount = 0;
132 for (
auto & node : lambdaNode.subregion()->Nodes())
134 if (is<AllocaOperation>(&node))
136 else if (is<StoreOperation>(&node))
138 else if (is<LoadOperation>(&node))
141 EXPECT_EQ(allocaCount, 0u);
142 EXPECT_EQ(storeCount, 0u);
143 EXPECT_EQ(loadCount, 0u);
146 const auto & result = *lambdaNode.GetFunctionResults()[0]->origin();
147 const auto resultValue = tryGetConstantSignedInteger(result);
148 EXPECT_EQ(resultValue, 20u);
151TEST(StoreValueForwardingTests, GetElementPointerOffsets)
176 auto & graph = rvsdgModule.
Rvsdg();
177 const auto bits32Type = rvsdg::BitType::Create(32);
178 const auto bits64Type = rvsdg::BitType::Create(64);
179 const auto byteType = rvsdg::BitType::Create(8);
180 const auto ioStateType = IOStateType::Create();
181 const auto memoryStateType = MemoryStateType::Create();
183 const auto funcType = rvsdg::FunctionType::Create(
184 { ioStateType, memoryStateType },
185 { bits64Type, bits32Type, bits32Type, ioStateType, memoryStateType });
188 auto & lambdaNode = *rvsdg::LambdaNode::Create(
189 graph.GetRootRegion(),
190 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
192 const auto io0 = lambdaNode.GetFunctionArguments()[0];
193 const auto mem0 = lambdaNode.GetFunctionArguments()[1];
195 auto & constantTwo = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2);
196 auto allocaAOutputs = AllocaOperation::create(bits32Type, constantTwo.output(0), 4);
199 auto & constantTwenty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 20);
200 auto & constantForty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 40);
203 auto & storeA40Node = StoreNonVolatileOperation::CreateNode(
205 *constantForty.output(0),
206 { allocaAOutputs[1] },
210 auto & constantOne = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 1);
212 GetElementPtrOperation::create(allocaAOutputs[0], { constantOne.output(0) }, bits32Type);
215 auto & storeB20Node = StoreNonVolatileOperation::CreateNode(
217 *constantTwenty.output(0),
218 { storeA40Node.output(0) },
222 auto & loadL1Node = LoadNonVolatileOperation::CreateNode(
224 { storeB20Node.output(0) },
229 auto & loadL2Node = LoadNonVolatileOperation::CreateNode(
231 { loadL1Node.output(1) },
236 auto & constantFour = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 4);
238 GetElementPtrOperation::create(allocaAOutputs[0], { constantFour.output(0) }, byteType);
242 LoadNonVolatileOperation::CreateNode(*gepCOutput, { loadL2Node.output(1) }, bits32Type, 4);
245 { loadL1Node.output(0), loadL2Node.output(0), loadL3Node.output(0), io0, mem0 });
255 size_t storeCount = 0;
256 size_t loadCount = 0;
258 for (
auto & node : lambdaNode.subregion()->Nodes())
260 if (is<StoreOperation>(&node))
262 else if (is<LoadOperation>(&node))
265 EXPECT_EQ(storeCount, 2u);
266 EXPECT_EQ(loadCount, 1u);
269 const auto results = lambdaNode.GetFunctionResults();
270 const auto r1 = tryGetConstantSignedInteger(*results[0]->origin());
271 const auto r2 = tryGetConstantSignedInteger(*results[1]->origin());
272 const auto r3 = tryGetConstantSignedInteger(*results[2]->origin());
273 EXPECT_FALSE(r1.has_value());
278TEST(StoreValueForwardingTests, RoutingIn)
306 auto & graph = rvsdgModule.
Rvsdg();
307 const auto pointerType = PointerType::Create();
308 const auto bits32Type = rvsdg::BitType::Create(32);
309 const auto ioStateType = IOStateType::Create();
310 const auto memoryStateType = MemoryStateType::Create();
311 const auto unitType = rvsdg::UnitType::Create();
313 const auto funcType = rvsdg::FunctionType::Create(
314 { pointerType, ioStateType, memoryStateType },
315 { bits32Type, ioStateType, memoryStateType });
318 auto & lambdaNode = *rvsdg::LambdaNode::Create(
319 graph.GetRootRegion(),
320 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
322 auto & q = *lambdaNode.GetFunctionArguments()[0];
323 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
324 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
327 auto & constantForty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 40);
330 auto & storeQ40Node =
331 StoreNonVolatileOperation::CreateNode(q, *constantForty.output(0), { &mem0 }, 4);
332 auto & mem1 = *StoreOperation::MemoryStateOutputs(storeQ40Node).begin();
335 auto & thetaNode = *rvsdg::ThetaNode::create(lambdaNode.subregion());
337 auto qLoopVar = thetaNode.AddLoopVar(&q);
338 auto memLoopVar = thetaNode.AddLoopVar(&mem1);
339 auto undefL = UndefValueOperation::Create(*lambdaNode.subregion(), bits32Type);
340 auto lLoopVar = thetaNode.AddLoopVar(undefL);
343 auto & predicate = *thetaNode.predicate()->origin();
344 auto & gammaNode = rvsdg::GammaNode::Create(predicate, 2, { unitType, unitType });
346 auto qEntryVar = gammaNode.AddEntryVar(qLoopVar.pre);
347 auto memEntryVar = gammaNode.AddEntryVar(memLoopVar.pre);
350 auto & loadNode = LoadNonVolatileOperation::CreateNode(
351 *qEntryVar.branchArgument[0],
352 { memEntryVar.branchArgument[0] },
355 auto & loadedValue = LoadOperation::LoadedValueOutput(loadNode);
356 auto & mem4 = *LoadOperation::MemoryStateOutputs(loadNode).begin();
359 auto & gammaSubregion1 = *gammaNode.subregion(1);
360 auto & constantSeventy = IntegerConstantOperation::Create(gammaSubregion1, 32, 70);
363 auto lExitVar = gammaNode.AddExitVar({ &loadedValue, constantSeventy.output(0) });
364 auto memExitVar = gammaNode.AddExitVar({ &mem4, memEntryVar.branchArgument[1] });
367 memLoopVar.post->divert_to(memExitVar.output);
368 lLoopVar.post->divert_to(lExitVar.output);
371 lambdaNode.finalize({ lLoopVar.output, &io0, memLoopVar.output });
373 std::cout << rvsdg::view(&graph.GetRootRegion()) << std::endl;
378 std::cout << rvsdg::view(&graph.GetRootRegion()) << std::endl;
383 auto & branch0Result = *lExitVar.branchResult[0]->origin();
384 auto resultValue = tryGetConstantSignedInteger(branch0Result);
385 EXPECT_EQ(resultValue, 40u);
389 EXPECT_EQ(&resultTraced, constantForty.output(0));
392TEST(StoreValueForwardingTests, RouteOut)
423 auto & graph = rvsdgModule.
Rvsdg();
424 const auto pointerType = PointerType::Create();
425 const auto bits32Type = rvsdg::BitType::Create(32);
426 const auto ioStateType = IOStateType::Create();
427 const auto memoryStateType = MemoryStateType::Create();
428 const auto unitType = rvsdg::UnitType::Create();
430 const auto funcType = rvsdg::FunctionType::Create(
431 { pointerType, ioStateType, memoryStateType },
432 { bits32Type, ioStateType, memoryStateType });
435 auto & lambdaNode = *rvsdg::LambdaNode::Create(
436 graph.GetRootRegion(),
437 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
439 auto & q = *lambdaNode.GetFunctionArguments()[0];
440 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
441 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
444 auto & constantForty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 40);
447 auto & storeQ40Node =
448 StoreNonVolatileOperation::CreateNode(q, *constantForty.output(0), { &mem0 }, 4);
449 auto & mem1 = *StoreOperation::MemoryStateOutputs(storeQ40Node).begin();
452 auto & thetaNode = *rvsdg::ThetaNode::create(lambdaNode.subregion());
454 auto qLoopVar = thetaNode.AddLoopVar(&q);
455 auto memLoopVar = thetaNode.AddLoopVar(&mem1);
458 auto & predicate = *thetaNode.predicate()->origin();
459 auto & gammaNode = rvsdg::GammaNode::Create(predicate, 2, { unitType, unitType });
461 auto qEntryVar = gammaNode.AddEntryVar(qLoopVar.pre);
462 auto memEntryVar = gammaNode.AddEntryVar(memLoopVar.pre);
465 auto & gammaSubregion0 = *gammaNode.subregion(0);
466 auto & constantTwenty = IntegerConstantOperation::Create(gammaSubregion0, 32, 20);
467 auto & storeQ20Node = StoreNonVolatileOperation::CreateNode(
468 *qEntryVar.branchArgument[0],
469 *constantTwenty.output(0),
470 { memEntryVar.branchArgument[0] },
472 auto & mem4 = *StoreOperation::MemoryStateOutputs(storeQ20Node).begin();
475 auto memExitVar = gammaNode.AddExitVar({ &mem4, memEntryVar.branchArgument[1] });
478 memLoopVar.post->divert_to(memExitVar.output);
482 LoadNonVolatileOperation::CreateNode(*qLoopVar.output, { memLoopVar.output }, bits32Type, 4);
483 auto & loadedValue = LoadOperation::LoadedValueOutput(loadNode);
484 auto & mem8 = *LoadOperation::MemoryStateOutputs(loadNode).begin();
487 lambdaNode.finalize({ &loadedValue, &io0, &mem8 });
499 const auto & resultOrigin = *lambdaNode.GetFunctionResults()[0]->origin();
500 const auto loopVar = thetaNode.MapOutputLoopVar(resultOrigin);
503 const auto & postOrigin = *loopVar.post->origin();
504 const auto exitVar = gammaNode.MapOutputExitVar(postOrigin);
506 const auto constInteger =
508 EXPECT_EQ(constInteger, 20u);
512 const auto loopVar2 = thetaNode.MapPreLoopVar(traced1stRegionOrigin);
513 EXPECT_EQ(loopVar.pre, loopVar2.pre);
516 EXPECT_EQ(constInputInteger, 40u);
519TEST(StoreValueForwardingTests, RouteAroundLoadLoop)
545 auto & graph = rvsdgModule.
Rvsdg();
546 const auto pointerType = PointerType::Create();
547 const auto bits32Type = rvsdg::BitType::Create(32);
548 const auto ioStateType = IOStateType::Create();
549 const auto memoryStateType = MemoryStateType::Create();
551 const auto funcType = rvsdg::FunctionType::Create(
552 { pointerType, ioStateType, memoryStateType },
553 { bits32Type, ioStateType, memoryStateType });
556 auto & lambdaNode = *rvsdg::LambdaNode::Create(
557 graph.GetRootRegion(),
558 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
560 auto & q = *lambdaNode.GetFunctionArguments()[0];
561 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
562 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
565 auto & constantForty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 40);
566 auto & storeQ40Node =
567 StoreNonVolatileOperation::CreateNode(q, *constantForty.output(0), { &mem0 }, 4);
568 auto & mem1 = *StoreOperation::MemoryStateOutputs(storeQ40Node).begin();
571 auto & thetaNode = *rvsdg::ThetaNode::create(lambdaNode.subregion());
572 auto qLoopVar = thetaNode.AddLoopVar(&q);
573 auto memLoopVar = thetaNode.AddLoopVar(&mem1);
574 auto undefL = UndefValueOperation::Create(*lambdaNode.subregion(), bits32Type);
575 auto lLoopVar = thetaNode.AddLoopVar(undefL);
577 auto & loadInLoopNode =
578 LoadNonVolatileOperation::CreateNode(*qLoopVar.pre, { memLoopVar.pre }, bits32Type, 4);
579 auto & l1 = LoadOperation::LoadedValueOutput(loadInLoopNode);
580 auto & mem3 = *LoadOperation::MemoryStateOutputs(loadInLoopNode).begin();
582 lLoopVar.post->divert_to(&l1);
583 memLoopVar.post->divert_to(&mem3);
586 auto & loadAfterLoopNode =
587 LoadNonVolatileOperation::CreateNode(q, { memLoopVar.output }, bits32Type, 4);
588 auto & l3 = LoadOperation::LoadedValueOutput(loadAfterLoopNode);
589 auto & mem5 = *LoadOperation::MemoryStateOutputs(loadAfterLoopNode).begin();
592 auto & addNode = rvsdg::CreateOpNode<IntegerAddOperation>({ lLoopVar.output, &l3 }, 32);
593 auto & add1 = *addNode.output(0);
596 lambdaNode.finalize({ &add1, &io0, &mem5 });
609 const auto & addLhsOrigin = *addNode.input(0)->origin();
610 const auto loopVar1 = thetaNode.MapOutputLoopVar(addLhsOrigin);
611 const auto loopVar2 = thetaNode.MapPreLoopVar(*loopVar1.post->origin());
612 EXPECT_TRUE(rvsdg::ThetaLoopVarIsInvariant(loopVar2));
613 EXPECT_EQ(tryGetConstantSignedInteger(*loopVar2.input->origin()), 40u);
616 const auto & addRhsOrigin = *addNode.input(1)->origin();
617 EXPECT_EQ(tryGetConstantSignedInteger(addRhsOrigin), 40u);
618 EXPECT_EQ(rvsdg::TryGetOwnerNode<rvsdg::ThetaNode>(addRhsOrigin),
nullptr);
621TEST(StoreValueForwardingTests, RouteUninitialized)
650 auto & graph = rvsdgModule.
Rvsdg();
651 const auto bits32Type = rvsdg::BitType::Create(32);
652 const auto ioStateType = IOStateType::Create();
653 const auto memoryStateType = MemoryStateType::Create();
654 const auto unitType = rvsdg::UnitType::Create();
656 const auto funcType = rvsdg::FunctionType::Create(
657 { ioStateType, memoryStateType },
658 { bits32Type, ioStateType, memoryStateType });
660 auto & lambdaNode = *rvsdg::LambdaNode::Create(
661 graph.GetRootRegion(),
662 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
664 auto & io0 = *lambdaNode.GetFunctionArguments()[0];
665 auto & mem0 = *lambdaNode.GetFunctionArguments()[1];
668 auto & constantOne = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 1);
669 auto allocaAOutputs = AllocaOperation::create(bits32Type, constantOne.output(0), 4);
672 auto & predicate = rvsdg::ControlConstantOperation::create(*lambdaNode.subregion(), 2, 0);
675 auto & gammaNode = rvsdg::GammaNode::Create(predicate, 2, { unitType, unitType });
676 auto aEntryVar = gammaNode.AddEntryVar(allocaAOutputs[0]);
677 auto memEntryVar = gammaNode.AddEntryVar(allocaAOutputs[1]);
680 auto & gammaSubregion0 = *gammaNode.subregion(0);
681 auto & constantTwenty = IntegerConstantOperation::Create(gammaSubregion0, 32, 20);
682 auto & storeA20Node = StoreNonVolatileOperation::CreateNode(
683 *aEntryVar.branchArgument[0],
684 *constantTwenty.output(0),
685 { memEntryVar.branchArgument[0] },
687 auto & mem3 = *StoreOperation::MemoryStateOutputs(storeA20Node).begin();
690 auto memExitVar = gammaNode.AddExitVar({ &mem3, memEntryVar.branchArgument[1] });
693 auto & loadNode = LoadNonVolatileOperation::CreateNode(
695 { memExitVar.output },
698 auto & ld = LoadOperation::LoadedValueOutput(loadNode);
700 lambdaNode.finalize({ &ld, &io0, &mem0 });
706 const auto & resultOrigin = *lambdaNode.GetFunctionResults()[0]->origin();
707 EXPECT_NE(rvsdg::TryGetOwnerNode<rvsdg::GammaNode>(resultOrigin),
nullptr);
709 const auto exitVar = gammaNode.MapOutputExitVar(resultOrigin);
711 const auto [undefNode, undefOperation] =
712 rvsdg::TryGetSimpleNodeAndOptionalOp<UndefValueOperation>(*exitVar.branchResult[1]->origin());
713 EXPECT_TRUE(undefNode && undefOperation);
716TEST(StoreValueForwardingTests, GepInLoop)
751 auto & graph = rvsdgModule.
Rvsdg();
752 const auto pointerType = PointerType::Create();
753 const auto bits32Type = rvsdg::BitType::Create(32);
754 const auto intArrayType = ArrayType::Create(bits32Type, 4);
755 const auto ioStateType = IOStateType::Create();
756 const auto memoryStateType = MemoryStateType::Create();
758 const auto funcType = rvsdg::FunctionType::Create(
759 { ioStateType, memoryStateType },
760 { bits32Type, ioStateType, memoryStateType });
762 auto & lambdaNode = *rvsdg::LambdaNode::Create(
763 graph.GetRootRegion(),
764 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
766 auto & io0 = *lambdaNode.GetFunctionArguments()[0];
767 auto & mem0 = *lambdaNode.GetFunctionArguments()[1];
769 auto & constantZero = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 0);
770 auto & constantOne = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 1);
771 auto & constantTwo = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2);
772 auto & constantThree = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 3);
773 auto & constantTwenty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 20);
774 auto & constantThirty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 30);
777 auto allocaAOutputs = AllocaOperation::create(intArrayType, constantOne.output(0), 4);
780 auto a2 = GetElementPtrOperation::create(
782 { constantZero.output(0), constantTwo.output(0) },
784 auto a3 = GetElementPtrOperation::create(
786 { constantZero.output(0), constantThree.output(0) },
790 auto & storeA220Node = StoreNonVolatileOperation::CreateNode(
792 *constantTwenty.output(0),
793 { allocaAOutputs[1] },
795 auto & mem1 = *StoreOperation::MemoryStateOutputs(storeA220Node).begin();
796 auto & storeA330Node =
797 StoreNonVolatileOperation::CreateNode(*a3, *constantThirty.output(0), { &mem1 }, 4);
798 auto & mem2 = *StoreOperation::MemoryStateOutputs(storeA330Node).begin();
801 auto & thetaNode = *rvsdg::ThetaNode::create(lambdaNode.subregion());
802 auto aLoopVar = thetaNode.AddLoopVar(allocaAOutputs[0]);
803 auto a2LoopVar = thetaNode.AddLoopVar(a2);
804 auto memLoopVar = thetaNode.AddLoopVar(&mem2);
807 auto & loadInLoopNode =
808 LoadNonVolatileOperation::CreateNode(*a2LoopVar.pre, { memLoopVar.pre }, bits32Type, 4);
809 auto & loadedValue = LoadOperation::LoadedValueOutput(loadInLoopNode);
810 auto & mem3 = *LoadOperation::MemoryStateOutputs(loadInLoopNode).begin();
813 auto & constantOneInLoop = IntegerConstantOperation::Create(*thetaNode.subregion(), 32, 1);
815 GetElementPtrOperation::create(aLoopVar.pre, { constantOneInLoop.output(0) }, bits32Type);
816 auto a22 = GetElementPtrOperation::create(a1, { constantOneInLoop.output(0) }, bits32Type);
819 auto & addLoadedOneNode =
820 rvsdg::CreateOpNode<IntegerAddOperation>({ &loadedValue, constantOneInLoop.output(0) }, 32);
821 auto & incrementedValue = *addLoadedOneNode.output(0);
822 auto & storeA22Node = StoreNonVolatileOperation::CreateNode(*a22, incrementedValue, { &mem3 }, 4);
823 auto & mem4 = *StoreOperation::MemoryStateOutputs(storeA22Node).begin();
826 auto & constantTen = IntegerConstantOperation::Create(*thetaNode.subregion(), 32, 10);
828 StoreNonVolatileOperation::CreateNode(*a1, *constantTen.output(0), { &mem4 }, 4);
829 auto & mem5 = *StoreOperation::MemoryStateOutputs(storeA1Node).begin();
831 memLoopVar.post->divert_to(&mem5);
834 auto & loadAfterLoopA2Node =
835 LoadNonVolatileOperation::CreateNode(*a2, { memLoopVar.output }, bits32Type, 4);
836 auto & loadedA2 = LoadOperation::LoadedValueOutput(loadAfterLoopA2Node);
837 auto & mem6 = *LoadOperation::MemoryStateOutputs(loadAfterLoopA2Node).begin();
838 auto & loadAfterLoopA3Node = LoadNonVolatileOperation::CreateNode(*a3, { &mem6 }, bits32Type, 4);
839 auto & loadedA3 = LoadOperation::LoadedValueOutput(loadAfterLoopA3Node);
840 auto & addResultNode = rvsdg::CreateOpNode<IntegerAddOperation>({ &loadedA2, &loadedA3 }, 32);
841 auto & resultValue = *addResultNode.output(0);
843 lambdaNode.finalize({ &resultValue, &io0, &mem0 });
845 std::cout << rvsdg::view(&graph.GetRootRegion()) << std::endl;
850 std::cout << rvsdg::view(&graph.GetRootRegion()) << std::endl;
856 const auto & loadedInLoopOrigin = *addLoadedOneNode.input(0)->origin();
857 const auto loadedLoopVar = thetaNode.MapPreLoopVar(loadedInLoopOrigin);
859 EXPECT_EQ(loadedLoopVar.post->origin(), addLoadedOneNode.output(0));
862 const auto & addLhsOrigin = *addResultNode.input(0)->origin();
863 const auto a2ResultLoopVar = thetaNode.MapOutputLoopVar(addLhsOrigin);
864 EXPECT_EQ(a2ResultLoopVar.post->origin(), addLoadedOneNode.output(0));
868 const auto & addRhsOrigin = *addResultNode.input(1)->origin();
869 EXPECT_EQ(&addRhsOrigin, constantThirty.output(0));
872TEST(StoreValueForwardingTests, LoadForwarding)
891 auto & graph = rvsdgModule.
Rvsdg();
892 const auto pointerType = PointerType::Create();
893 const auto bits32Type = rvsdg::BitType::Create(32);
894 const auto ioStateType = IOStateType::Create();
895 const auto memoryStateType = MemoryStateType::Create();
897 const auto funcType = rvsdg::FunctionType::Create(
898 { pointerType, ioStateType, memoryStateType },
899 { bits32Type, ioStateType, memoryStateType });
901 auto & lambdaNode = *rvsdg::LambdaNode::Create(
902 graph.GetRootRegion(),
903 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
905 auto & p = *lambdaNode.GetFunctionArguments()[0];
906 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
907 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
909 auto & load1Node = LoadNonVolatileOperation::CreateNode(p, { &mem0 }, bits32Type, 4);
910 auto & l1 = LoadOperation::LoadedValueOutput(load1Node);
911 auto & mem1 = *LoadOperation::MemoryStateOutputs(load1Node).begin();
913 auto & load2Node = LoadNonVolatileOperation::CreateNode(p, { &mem1 }, bits32Type, 4);
914 auto & l2 = LoadOperation::LoadedValueOutput(load2Node);
915 auto & mem2 = *LoadOperation::MemoryStateOutputs(load2Node).begin();
917 auto & addNode = rvsdg::CreateOpNode<IntegerAddOperation>({ &l1, &l2 }, 32);
918 auto & add0 = *addNode.output(0);
920 lambdaNode.finalize({ &add0, &io0, &mem2 });
926 size_t loadCount = 0;
927 for (
auto & node : lambdaNode.subregion()->Nodes())
929 if (is<LoadOperation>(&node))
932 EXPECT_EQ(loadCount, 1u);
936 EXPECT_EQ(&addLhsOrigin, &l1);
937 EXPECT_EQ(&addRhsOrigin, &l1);
939 const auto & memoryResultOrigin =
941 EXPECT_EQ(&memoryResultOrigin, &mem1);
944TEST(StoreValueForwardingTests, LoadForwardingIntoTheta)
970 auto & graph = rvsdgModule.
Rvsdg();
971 const auto pointerType = PointerType::Create();
972 const auto bits32Type = rvsdg::BitType::Create(32);
973 const auto ioStateType = IOStateType::Create();
974 const auto memoryStateType = MemoryStateType::Create();
976 const auto funcType = rvsdg::FunctionType::Create(
977 { pointerType, ioStateType, memoryStateType },
978 { bits32Type, ioStateType, memoryStateType });
980 auto & lambdaNode = *rvsdg::LambdaNode::Create(
981 graph.GetRootRegion(),
982 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
984 auto & p = *lambdaNode.GetFunctionArguments()[0];
985 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
986 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
988 auto & load1Node = LoadNonVolatileOperation::CreateNode(p, { &mem0 }, bits32Type, 4);
989 auto & l1 = LoadOperation::LoadedValueOutput(load1Node);
990 auto & mem1 = *LoadOperation::MemoryStateOutputs(load1Node).begin();
992 auto & thetaNode = *rvsdg::ThetaNode::create(lambdaNode.subregion());
993 auto pLoopVar = thetaNode.AddLoopVar(&p);
994 auto sumLoopVar = thetaNode.AddLoopVar(&l1);
995 auto memLoopVar = thetaNode.AddLoopVar(&mem1);
998 LoadNonVolatileOperation::CreateNode(*pLoopVar.pre, { memLoopVar.pre }, bits32Type, 4);
999 auto & l2 = LoadOperation::LoadedValueOutput(load2Node);
1000 auto & mem3 = *LoadOperation::MemoryStateOutputs(load2Node).begin();
1002 auto & addNode = rvsdg::CreateOpNode<IntegerAddOperation>({ sumLoopVar.pre, &l2 }, 32);
1003 auto & sum2 = *addNode.output(0);
1005 auto & constant100 = IntegerConstantOperation::Create(*thetaNode.subregion(), 32, 100);
1006 auto & sltNode = rvsdg::CreateOpNode<IntegerSltOperation>({ &sum2, constant100.output(0) }, 32);
1007 const auto predicate = rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
1009 thetaNode.set_predicate(predicate);
1010 sumLoopVar.post->divert_to(&sum2);
1011 memLoopVar.post->divert_to(&mem3);
1013 lambdaNode.finalize({ sumLoopVar.output, &io0, memLoopVar.output });
1019 size_t lambdaLoadCount = 0;
1020 for (
auto & node : lambdaNode.subregion()->Nodes())
1022 if (is<LoadOperation>(&node))
1025 EXPECT_EQ(lambdaLoadCount, 1u);
1027 size_t thetaLoadCount = 0;
1028 for (
auto & node : thetaNode.subregion()->Nodes())
1030 if (is<LoadOperation>(&node))
1033 EXPECT_EQ(thetaLoadCount, 0u);
1036 EXPECT_EQ(&addLhsOrigin, sumLoopVar.pre);
1038 const auto & addRhsOrigin = *addNode.input(1)->origin();
1039 const auto forwardedLoopVar = thetaNode.MapPreLoopVar(addRhsOrigin);
1040 EXPECT_TRUE(rvsdg::ThetaLoopVarIsInvariant(forwardedLoopVar));
1041 EXPECT_EQ(forwardedLoopVar.input->origin(), &l1);
1044 const auto & memoryResultOrigin =
1046 EXPECT_EQ(&memoryResultOrigin, &mem1);
1049TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithIntegerConstant)
1056 auto & graph = rvsdgModule.
Rvsdg();
1058 const auto pointerType = PointerType::Create();
1059 const auto bits8Type = BitType::Create(8);
1060 const auto bits32Type = BitType::Create(32);
1061 const auto functionType = FunctionType::Create(
1068 auto deltaNode = DeltaNode::Create(
1069 &graph.GetRootRegion(),
1070 DeltaOperation::Create(bits32Type,
true, pointerType));
1071 auto & four = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 4);
1072 auto & deltaOutput = deltaNode->finalize(four.output(0));
1074 auto & lambdaNode = *LambdaNode::Create(
1075 graph.GetRootRegion(),
1076 LlvmLambdaOperation::Create(functionType,
"func", Linkage::internalLinkage));
1077 auto ctxVar = lambdaNode.AddContextVar(deltaOutput);
1079 auto & load32Node = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits32Type, 4);
1080 auto & load8Node = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits8Type, 4);
1082 lambdaNode.finalize({ &LoadOperation::LoadedValueOutput(load32Node),
1083 &LoadOperation::LoadedValueOutput(load8Node) });
1090 auto [intNode0, intOperation0] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1091 *lambdaNode.GetFunctionResults()[0]->origin());
1092 EXPECT_NE(intOperation0,
nullptr);
1093 EXPECT_EQ(intOperation0->Representation().nbits(), 32u);
1094 EXPECT_EQ(intOperation0->Representation().to_uint(), 4u);
1098 auto [truncNode, truncOperation] = TryGetSimpleNodeAndOptionalOp<TruncOperation>(
1099 *lambdaNode.GetFunctionResults()[1]->origin());
1100 EXPECT_NE(truncOperation,
nullptr);
1102 auto [intNode1, intOperation1] =
1103 TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*truncNode->input(0)->origin());
1104 EXPECT_NE(intOperation1,
nullptr);
1105 EXPECT_EQ(intOperation1->Representation().nbits(), 32u);
1106 EXPECT_EQ(intOperation1->Representation().to_uint(), 4u);
1110TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithAggregateZeroConstant)
1117 auto & graph = rvsdgModule.
Rvsdg();
1119 const auto pointerType = PointerType::Create();
1120 const auto bits32Type = BitType::Create(32);
1121 const auto fixedVectorType = FixedVectorType::Create(bits32Type, 4);
1122 const auto floatType = FloatingPointType::Create(fpsize::flt);
1123 const auto doubleType = FloatingPointType::Create(fpsize::dbl);
1124 const auto structType = StructType::CreateIdentified(
1126 { bits32Type, pointerType, fixedVectorType, floatType, doubleType },
1128 const auto functionType =
1129 FunctionType::Create({}, { bits32Type, pointerType, fixedVectorType, floatType, doubleType });
1131 auto deltaNode = DeltaNode::Create(
1132 &graph.GetRootRegion(),
1133 DeltaOperation::Create(structType,
true, pointerType));
1134 auto aggregateZero = ConstantAggregateZeroOperation::Create(*deltaNode->subregion(), structType);
1135 auto & deltaOutput = deltaNode->finalize(aggregateZero);
1137 auto & lambdaNode = *LambdaNode::Create(
1138 graph.GetRootRegion(),
1139 LlvmLambdaOperation::Create(functionType,
"func", Linkage::internalLinkage));
1140 auto ctxVar = lambdaNode.AddContextVar(deltaOutput);
1142 auto & zeroNode = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 0);
1143 auto & oneNode = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 1);
1144 auto & twoNode = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2);
1145 auto & threeNode = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 3);
1146 auto & fourNode = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 4);
1148 auto & gep0Node = GetElementPtrOperation::createNode(
1150 { zeroNode.output(0), zeroNode.output(0) },
1152 auto & load32Node = LoadNonVolatileOperation::CreateNode(*gep0Node.output(0), {}, bits32Type, 4);
1154 auto & gep1Node = GetElementPtrOperation::createNode(
1156 { zeroNode.output(0), oneNode.output(0) },
1158 auto & loadPtrNode =
1159 LoadNonVolatileOperation::CreateNode(*gep1Node.output(0), {}, pointerType, 4);
1161 auto & gep2Node = GetElementPtrOperation::createNode(
1163 { zeroNode.output(0), twoNode.output(0) },
1165 auto & loadV32Node =
1166 LoadNonVolatileOperation::CreateNode(*gep2Node.output(0), {}, fixedVectorType, 4);
1168 auto & gepFloatNode = GetElementPtrOperation::createNode(
1170 { zeroNode.output(0), threeNode.output(0) },
1172 auto & loadFloatNode =
1173 LoadNonVolatileOperation::CreateNode(*gepFloatNode.output(0), {}, floatType, 4);
1175 auto & gepDoubleNode = GetElementPtrOperation::createNode(
1177 { zeroNode.output(0), fourNode.output(0) },
1179 auto & loadDoubleNode =
1180 LoadNonVolatileOperation::CreateNode(*gepDoubleNode.output(0), {}, doubleType, 8);
1182 lambdaNode.finalize({
1183 &LoadOperation::LoadedValueOutput(load32Node),
1184 &LoadOperation::LoadedValueOutput(loadPtrNode),
1185 &LoadOperation::LoadedValueOutput(loadV32Node),
1186 &LoadOperation::LoadedValueOutput(loadFloatNode),
1187 &LoadOperation::LoadedValueOutput(loadDoubleNode),
1195 EXPECT_FALSE(Region::containsOperation<LoadNonVolatileOperation>(graph.GetRootRegion(),
true));
1198 auto [intNode, intOperation] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1199 *lambdaNode.GetFunctionResults()[0]->origin());
1200 EXPECT_NE(intOperation,
nullptr);
1201 EXPECT_EQ(intOperation->Representation().to_uint(), 0u);
1205 auto [nullPtrNode, nullPtrOperation] =
1206 TryGetSimpleNodeAndOptionalOp<ConstantPointerNullOperation>(
1207 *lambdaNode.GetFunctionResults()[1]->origin());
1208 EXPECT_NE(nullPtrOperation,
nullptr);
1212 auto [aggZeroNode, aggZeroOperation] =
1213 TryGetSimpleNodeAndOptionalOp<ConstantAggregateZeroOperation>(
1214 *lambdaNode.GetFunctionResults()[2]->origin());
1215 EXPECT_NE(aggZeroOperation,
nullptr);
1219 auto [floatNode, floatOperation] =
1220 TryGetSimpleNodeAndOptionalOp<ConstantFP>(*lambdaNode.GetFunctionResults()[3]->origin());
1221 EXPECT_NE(floatOperation,
nullptr);
1222 EXPECT_EQ(&floatOperation->constant().getSemantics(), &llvm::APFloat::IEEEsingle());
1223 EXPECT_TRUE(floatOperation->constant().isZero());
1227 auto [doubleNode, doubleOperation] =
1228 TryGetSimpleNodeAndOptionalOp<ConstantFP>(*lambdaNode.GetFunctionResults()[4]->origin());
1229 EXPECT_NE(doubleOperation,
nullptr);
1230 EXPECT_EQ(&doubleOperation->constant().getSemantics(), &llvm::APFloat::IEEEdouble());
1231 EXPECT_TRUE(doubleOperation->constant().isZero());
1235TEST(StoreValueForwardingTests, LoadForwardingFromDeltaCtxVar)
1242 auto & graph = rvsdgModule.
Rvsdg();
1243 const auto pointerType = PointerType::Create();
1244 const auto bits32Type = BitType::Create(32);
1245 const auto functionType = FunctionType::Create(
1251 auto deltaNode1 = DeltaNode::Create(
1252 &graph.GetRootRegion(),
1253 DeltaOperation::Create(bits32Type,
true, pointerType));
1254 auto & four = IntegerConstantOperation::Create(*deltaNode1->subregion(), 32, 4);
1255 auto & deltaOutput1 = deltaNode1->finalize(four.output(0));
1257 auto deltaNode2 = DeltaNode::Create(
1258 &graph.GetRootRegion(),
1259 DeltaOperation::Create(pointerType,
true, pointerType));
1260 auto deltaCtxVar = deltaNode2->AddContextVar(deltaOutput1);
1261 auto & deltaOutput2 = deltaNode2->finalize(deltaCtxVar.inner);
1263 auto & lambdaNode = *LambdaNode::Create(
1264 graph.GetRootRegion(),
1265 LlvmLambdaOperation::Create(functionType,
"func", Linkage::internalLinkage));
1266 auto ctxVar = lambdaNode.AddContextVar(deltaOutput2);
1268 auto & loadNode = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, pointerType, 4);
1270 lambdaNode.finalize({ &LoadOperation::LoadedValueOutput(loadNode) });
1277 EXPECT_FALSE(Region::containsOperation<LoadNonVolatileOperation>(graph.GetRootRegion(),
true));
1279 EXPECT_EQ(deltaOutput1.nusers(), 2u);
1362TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithConstantDataArray)
1369 auto & graph = rvsdgModule.
Rvsdg();
1370 const auto pointerType = PointerType::Create();
1371 const auto bits8Type = BitType::Create(8);
1372 const auto bits32Type = BitType::Create(32);
1373 const auto bits64Type = BitType::Create(64);
1374 const auto arrayType = ArrayType::Create(bits32Type, 3);
1375 const auto functionType = FunctionType::Create(
1386 auto deltaNode = DeltaNode::Create(
1387 &graph.GetRootRegion(),
1388 DeltaOperation::Create(arrayType,
true, pointerType));
1389 auto & zeroNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 0);
1390 auto & oneNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 1);
1391 auto & twoNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 2);
1392 auto constantDataArrayResult = ConstantDataArrayOperation::Create(
1393 { zeroNode.output(0), oneNode.output(0), twoNode.output(0) });
1394 auto & deltaOutput = deltaNode->finalize(constantDataArrayResult);
1396 auto & lambdaNode = *LambdaNode::Create(
1397 graph.GetRootRegion(),
1398 LlvmLambdaOperation::Create(functionType,
"func", Linkage::internalLinkage));
1399 auto ctxVar = lambdaNode.AddContextVar(deltaOutput);
1401 auto zero = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 0).output(0);
1402 auto two = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2).output(0);
1403 auto four = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 4).output(0);
1405 auto & loadNode0 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits32Type, 4);
1407 auto gepOutput1 = GetElementPtrOperation::create(ctxVar.inner, { zero }, bits32Type);
1408 auto & loadNode1 = LoadNonVolatileOperation::CreateNode(*gepOutput1, {}, bits32Type, 4);
1410 auto gepOutput2 = GetElementPtrOperation::create(ctxVar.inner, { zero, zero }, arrayType);
1411 auto & loadNode2 = LoadNonVolatileOperation::CreateNode(*gepOutput2, {}, bits32Type, 4);
1413 auto gepOutput3 = GetElementPtrOperation::create(ctxVar.inner, { zero, two }, arrayType);
1414 auto & loadNode3 = LoadNonVolatileOperation::CreateNode(*gepOutput3, {}, bits32Type, 4);
1416 auto gepOutput4 = GetElementPtrOperation::create(ctxVar.inner, { four }, bits8Type);
1417 auto & loadNode4 = LoadNonVolatileOperation::CreateNode(*gepOutput4, {}, bits32Type, 4);
1419 auto & loadNode5 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits64Type, 4);
1421 lambdaNode.finalize({
1422 &LoadOperation::LoadedValueOutput(loadNode0),
1423 &LoadOperation::LoadedValueOutput(loadNode1),
1424 &LoadOperation::LoadedValueOutput(loadNode2),
1425 &LoadOperation::LoadedValueOutput(loadNode3),
1426 &LoadOperation::LoadedValueOutput(loadNode4),
1427 &LoadOperation::LoadedValueOutput(loadNode5),
1434 auto [intNode0, intOperation0] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1435 *lambdaNode.GetFunctionResults()[0]->origin());
1436 EXPECT_NE(intOperation0,
nullptr);
1437 EXPECT_EQ(intOperation0->Representation().to_uint(), 0u);
1439 auto [intNode1, intOperation1] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1440 *lambdaNode.GetFunctionResults()[1]->origin());
1441 EXPECT_NE(intOperation1,
nullptr);
1442 EXPECT_EQ(intOperation1->Representation().to_uint(), 0u);
1444 auto [intNode2, intOperation2] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1445 *lambdaNode.GetFunctionResults()[2]->origin());
1446 EXPECT_NE(intOperation2,
nullptr);
1447 EXPECT_EQ(intOperation2->Representation().to_uint(), 0u);
1449 auto [intNode3, intOperation3] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1450 *lambdaNode.GetFunctionResults()[3]->origin());
1451 EXPECT_NE(intOperation3,
nullptr);
1452 EXPECT_EQ(intOperation3->Representation().to_uint(), 2u);
1454 auto [intNode4, intOperation4] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1455 *lambdaNode.GetFunctionResults()[4]->origin());
1456 EXPECT_NE(intOperation4,
nullptr);
1457 EXPECT_EQ(intOperation4->Representation().to_uint(), 1u);
1461 auto [loadNode, loadOperation] = TryGetSimpleNodeAndOptionalOp<LoadNonVolatileOperation>(
1462 *lambdaNode.GetFunctionResults()[5]->origin());
1463 EXPECT_NE(loadOperation,
nullptr);
1465 auto [intNode5, intOperation5] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1466 *lambdaNode.GetFunctionResults()[5]->origin());
1467 EXPECT_NE(intOperation5,
nullptr);
1468 EXPECT_EQ(intOperation5->Representation().to_uint(), 0x0000000100000000u);
1473TEST(StoreValueForwardingTests, RegionPredicatedValueForwarding)
1475 using namespace jlm;
1512 auto & graph = rvsdgModule.
Rvsdg();
1513 const auto pointerType = PointerType::Create();
1514 const auto bit32Type = rvsdg::BitType::Create(32);
1515 const auto memoryStateType = MemoryStateType::Create();
1517 const auto funcType =
1518 rvsdg::FunctionType::Create({ pointerType, memoryStateType }, { bit32Type, memoryStateType });
1520 auto & lambdaNode = *rvsdg::LambdaNode::Create(
1521 graph.GetRootRegion(),
1522 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
1524 auto & p = *lambdaNode.GetFunctionArguments()[0];
1525 auto & mem0 = *lambdaNode.GetFunctionArguments()[1];
1528 auto & ctrlZero = rvsdg::ControlConstantOperation::create(*lambdaNode.subregion(), 2, 0);
1529 auto & gamma1 = *rvsdg::GammaNode::create(&ctrlZero, 2);
1531 auto gamma1PEntry = gamma1.AddEntryVar(&p);
1532 auto gamma1MemEntr = gamma1.AddEntryVar(&mem0);
1535 auto & constantForty = IntegerConstantOperation::Create(*gamma1.subregion(0), 32, 40);
1536 auto & storeP40Node = StoreNonVolatileOperation::CreateNode(
1537 *gamma1PEntry.branchArgument[0],
1538 *constantForty.output(0),
1539 { gamma1MemEntr.branchArgument[0] },
1541 auto & gamma1LeftMem = *StoreOperation::MemoryStateOutputs(storeP40Node).begin();
1542 auto & gamma1LeftCtrl = rvsdg::ControlConstantOperation::create(*gamma1.subregion(0), 2, 0);
1545 auto & gamma1RightCtrl = rvsdg::ControlConstantOperation::create(*gamma1.subregion(1), 2, 1);
1548 auto gamma1CtrlExit = gamma1.AddExitVar({ &gamma1LeftCtrl, &gamma1RightCtrl });
1549 auto gamma1MemExit = gamma1.AddExitVar({ &gamma1LeftMem, gamma1MemEntr.branchArgument[1] });
1552 auto & gamma2 = *rvsdg::GammaNode::create(gamma1CtrlExit.output, 2);
1554 auto gamma2PEntry = gamma2.AddEntryVar(&p);
1555 auto gamma2MemEntry = gamma2.AddEntryVar(gamma1MemExit.output);
1558 auto & loadPLeft = LoadNonVolatileOperation::CreateNode(
1559 *gamma2PEntry.branchArgument[0],
1560 { gamma2MemEntry.branchArgument[0] },
1563 auto & loadedPLeft = LoadNonVolatileOperation::LoadedValueOutput(loadPLeft);
1564 auto & memLeft = *LoadNonVolatileOperation::MemoryStateOutputs(loadPLeft).begin();
1567 auto & loadPRight = LoadNonVolatileOperation::CreateNode(
1568 *gamma2PEntry.branchArgument[1],
1569 { gamma2MemEntry.branchArgument[1] },
1572 auto & loadedPRight = LoadNonVolatileOperation::LoadedValueOutput(loadPRight);
1573 auto & memRight = *LoadNonVolatileOperation::MemoryStateOutputs(loadPRight).begin();
1576 auto gamma2ExitLoadedP = gamma2.AddExitVar({ &loadedPLeft, &loadedPRight });
1577 auto gamma2ExitMem = gamma2.AddExitVar({ &memLeft, &memRight });
1580 lambdaNode.finalize({ gamma2ExitLoadedP.output, gamma2ExitMem.output });
1589 const auto & leftPOrigin = *gamma2ExitLoadedP.branchResult[0]->origin();
1592 auto gamma = rvsdg::TryGetOwnerNode<rvsdg::GammaNode>(tracedLeftPOrigin);
1593 ASSERT_EQ(gamma, &gamma1);
1595 auto exitVarP = gamma->MapOutputExitVar(tracedLeftPOrigin);
1597 auto & leftG1Origin = *exitVarP.branchResult[0]->origin();
1598 ASSERT_TRUE(rvsdg::IsOwnerNodeOperation<IntegerConstantOperation>(leftG1Origin));
1602 auto & rightG1Origin = *exitVarP.branchResult[1]->origin();
1603 ASSERT_TRUE(rvsdg::IsOwnerNodeOperation<UndefValueOperation>(rightG1Origin));
1606 const auto & rightPOrigin = *gamma2ExitLoadedP.branchResult[1]->origin();
1607 ASSERT_TRUE(rvsdg::IsOwnerNodeOperation<LoadNonVolatileOperation>(rightPOrigin));
1610TEST(StoreValueForwardingTests, LoadForwardingFromLoopExiting)
1612 using namespace jlm;
1682 auto & graph = rvsdgModule.
Rvsdg();
1683 const auto pointerType = PointerType::Create();
1684 const auto bits32Type = rvsdg::BitType::Create(32);
1685 const auto ioStateType = IOStateType::Create();
1686 const auto memoryStateType = MemoryStateType::Create();
1687 const auto unitType = rvsdg::UnitType::Create();
1688 const auto controlType = rvsdg::ControlType::Create(2);
1691 const auto opaqueFuncType = rvsdg::FunctionType::Create(
1692 { ioStateType, memoryStateType },
1693 { ioStateType, memoryStateType });
1695 auto & opaqueImport = LlvmGraphImport::createFunctionImport(
1699 Linkage::externalLinkage,
1700 CallingConvention::Default);
1703 const auto funcType = rvsdg::FunctionType::Create(
1704 { pointerType, pointerType, ioStateType, memoryStateType },
1705 { bits32Type, ioStateType, memoryStateType });
1707 auto & lambdaNode = *rvsdg::LambdaNode::Create(
1708 graph.GetRootRegion(),
1709 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
1711 auto & p = *lambdaNode.GetFunctionArguments()[0];
1712 auto & q = *lambdaNode.GetFunctionArguments()[1];
1713 auto & io0 = *lambdaNode.GetFunctionArguments()[2];
1714 auto & mem0 = *lambdaNode.GetFunctionArguments()[3];
1717 auto opaqueCtxVar = lambdaNode.AddContextVar(opaqueImport);
1721 auto & thetaNode = *rvsdg::ThetaNode::create(lambdaNode.subregion());
1723 auto exitPredInit = UndefValueOperation::Create(*lambdaNode.subregion(), controlType);
1724 auto exitPredLoopVar = thetaNode.AddLoopVar(exitPredInit);
1725 auto pLoopVar = thetaNode.AddLoopVar(&p);
1726 auto qLoopVar = thetaNode.AddLoopVar(&q);
1727 auto memLoopVar = thetaNode.AddLoopVar(&mem0);
1728 auto ioLoopVar = thetaNode.AddLoopVar(&io0);
1729 auto opaqueLoopVar = thetaNode.AddLoopVar(opaqueCtxVar.inner);
1733 auto & callOpqNode = CallOperation::CreateNode(
1736 { ioLoopVar.pre, memLoopVar.pre });
1737 auto & io2 = CallOperation::GetIOStateOutput(callOpqNode);
1738 auto & mem2 = CallOperation::GetMemoryStateOutput(callOpqNode);
1741 auto & loadPNode = LoadNonVolatileOperation::CreateNode(*pLoopVar.pre, { &mem2 }, bits32Type, 4);
1742 auto & pLoad = LoadOperation::LoadedValueOutput(loadPNode);
1743 auto & mem3 = *LoadOperation::MemoryStateOutputs(loadPNode).begin();
1746 auto & constantZero = IntegerConstantOperation::Create(*thetaNode.subregion(), 32, 0);
1749 auto & neqCondNode =
1750 rvsdg::CreateOpNode<IntegerNeOperation>({ &pLoad, constantZero.output(0) }, 32);
1751 auto & gamma1Cond = *neqCondNode.output(0);
1754 const auto matchMapping = std::unordered_map<uint64_t, uint64_t>{ { 1, 1 } };
1755 auto & gamma1PredNode =
1756 rvsdg::CreateOpNode<rvsdg::MatchOperation>({ &gamma1Cond }, 1, matchMapping, 0, 2);
1757 auto & gamma1Pred = *gamma1PredNode.output(0);
1761 auto & outerGammaNode = rvsdg::GammaNode::Create(gamma1Pred, 2, { unitType, unitType });
1762 auto qEntryVar = outerGammaNode.AddEntryVar(qLoopVar.pre);
1763 auto memEntryVar = outerGammaNode.AddEntryVar(&mem3);
1768 auto & gammaSubregion0 = *outerGammaNode.subregion(0);
1769 auto & ctrlZeroOuter = rvsdg::ControlConstantOperation::create(gammaSubregion0, 2, 0);
1772 auto & gammaSubregion1 = *outerGammaNode.subregion(1);
1775 auto & loadQNode = LoadNonVolatileOperation::CreateNode(
1776 *qEntryVar.branchArgument[1],
1777 { memEntryVar.branchArgument[1] },
1780 auto & qLoad = LoadOperation::LoadedValueOutput(loadQNode);
1781 auto & mem6 = *LoadOperation::MemoryStateOutputs(loadQNode).begin();
1784 auto & constantZeroInner = IntegerConstantOperation::Create(gammaSubregion1, 32, 0);
1787 auto & neqCondInnerNode =
1788 rvsdg::CreateOpNode<IntegerNeOperation>({ &qLoad, constantZeroInner.output(0) }, 32);
1789 auto & gamma2Cond = *neqCondInnerNode.output(0);
1792 auto & gamma2PredNode =
1793 rvsdg::CreateOpNode<rvsdg::MatchOperation>({ &gamma2Cond }, 1, matchMapping, 0, 2);
1794 auto & gamma2Pred = *gamma2PredNode.output(0);
1799 auto & innerGammaNode = rvsdg::GammaNode::Create(gamma2Pred, 2, {});
1802 auto & innerGammaBranch0 = *innerGammaNode.subregion(0);
1803 auto & ctrlZero1 = rvsdg::ControlConstantOperation::create(innerGammaBranch0, 2, 0);
1804 auto & ctrlOne1 = rvsdg::ControlConstantOperation::create(innerGammaBranch0, 2, 1);
1806 auto & innerGammaBranch1 = *innerGammaNode.subregion(1);
1807 auto & ctrlOne2 = rvsdg::ControlConstantOperation::create(innerGammaBranch1, 2, 1);
1809 auto innerLoopPredExitVar = innerGammaNode.AddExitVar({ &ctrlZero1, &ctrlOne2 });
1810 auto innerExitPredExitVar = innerGammaNode.AddExitVar({ &ctrlOne1, &ctrlOne2 });
1813 auto outerLoopPredExitVar =
1814 outerGammaNode.AddExitVar({ &ctrlZeroOuter, innerLoopPredExitVar.output });
1815 auto outerExitPredExitVar =
1816 outerGammaNode.AddExitVar({ &ctrlZeroOuter, innerExitPredExitVar.output });
1820 auto memExitVar = outerGammaNode.AddExitVar({ memEntryVar.branchArgument[0], &mem6 });
1823 thetaNode.predicate()->divert_to(outerLoopPredExitVar.output);
1824 exitPredLoopVar.post->divert_to(outerLoopPredExitVar.output);
1825 memLoopVar.post->divert_to(memExitVar.output);
1826 ioLoopVar.post->divert_to(&io2);
1827 opaqueLoopVar.post->divert_to(opaqueLoopVar.pre);
1834 auto & exitGammaNode = *rvsdg::GammaNode::create(exitPredLoopVar.output, 2);
1835 auto pEntryVarExit = exitGammaNode.AddEntryVar(&p);
1836 auto qEntryVarExit = exitGammaNode.AddEntryVar(&q);
1837 auto memEntryVarExit = exitGammaNode.AddEntryVar(memLoopVar.output);
1840 auto & loadP2Node = LoadNonVolatileOperation::CreateNode(
1841 *pEntryVarExit.branchArgument[0],
1842 { memEntryVarExit.branchArgument[0] },
1845 auto & pLoad2 = LoadOperation::LoadedValueOutput(loadP2Node);
1846 auto & mem10 = *LoadOperation::MemoryStateOutputs(loadP2Node).begin();
1849 auto & loadQ2Node = LoadNonVolatileOperation::CreateNode(
1850 *qEntryVarExit.branchArgument[1],
1851 { memEntryVarExit.branchArgument[1] },
1854 auto & qLoad2 = LoadOperation::LoadedValueOutput(loadQ2Node);
1855 auto & mem12 = *LoadOperation::MemoryStateOutputs(loadQ2Node).begin();
1857 auto retExitVar = exitGammaNode.AddExitVar({ &pLoad2, &qLoad2 });
1858 auto memFinalExitVar = exitGammaNode.AddExitVar({ &mem10, &mem12 });
1861 lambdaNode.finalize({ retExitVar.output, ioLoopVar.output, memFinalExitVar.output });
1863 std::cout << rvsdg::view(&graph.GetRootRegion()) << std::endl;
1871 rvsdg::TryGetRegionParentNode<rvsdg::GammaNode>(*retExitVar.branchResult[0]->origin()));
1873 rvsdg::TryGetRegionParentNode<rvsdg::GammaNode>(*retExitVar.branchResult[1]->origin()));
1875 ASSERT_EQ(pLoad.nusers(), 2u);
1876 ASSERT_EQ(qLoad.nusers(), 2u);
1879TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithConstantStruct)
1885 const auto pointerType = PointerType::Create();
1886 const auto bits8Type = BitType::Create(8);
1887 const auto bits32Type = BitType::Create(32);
1888 const auto bits64Type = BitType::Create(64);
1889 const auto structType = StructType::CreateIdentified(
1890 { bits32Type, bits32Type, bits32Type, bits32Type, pointerType },
1892 auto functionType1 = FunctionType::Create({}, {});
1893 const auto functionType2 = FunctionType::Create(
1895 { bits32Type, bits32Type, bits32Type, bits32Type, bits32Type, bits64Type, pointerType });
1898 auto & graph = rvsdgModule.Rvsdg();
1900 auto & i0 = GraphImport::Create(graph, functionType2,
"fct");
1902 auto deltaNode = DeltaNode::Create(
1903 &graph.GetRootRegion(),
1904 DeltaOperation::Create(structType,
true, pointerType));
1906 auto ctxVar = deltaNode->AddContextVar(i0);
1907 auto & zeroNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 0);
1908 auto & oneNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 1);
1909 auto & twoNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 2);
1910 auto & threeNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 3);
1911 auto & fnToPtrNode = FunctionToPointerOperation::createNode(*ctxVar.inner);
1912 auto & constantStructResult = ConstantStructOperation::Create(
1913 *deltaNode->subregion(),
1914 { zeroNode.output(0),
1917 threeNode.output(0),
1918 fnToPtrNode.output(0) },
1920 deltaNode->finalize(&constantStructResult);
1923 auto & lambdaNode = *LambdaNode::Create(
1924 graph.GetRootRegion(),
1925 LlvmLambdaOperation::Create(functionType2,
"func", Linkage::internalLinkage));
1926 auto ctxVar = lambdaNode.AddContextVar(deltaNode->output());
1928 auto zero = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 0).output(0);
1929 auto two = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2).output(0);
1930 auto four = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 4).output(0);
1932 auto & loadNode0 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits32Type, 4);
1934 auto gepOutput1 = GetElementPtrOperation::create(ctxVar.inner, { zero }, bits32Type);
1935 auto & loadNode1 = LoadNonVolatileOperation::CreateNode(*gepOutput1, {}, bits32Type, 4);
1937 auto gepOutput2 = GetElementPtrOperation::create(ctxVar.inner, { zero, zero }, structType);
1938 auto & loadNode2 = LoadNonVolatileOperation::CreateNode(*gepOutput2, {}, bits32Type, 4);
1940 auto gepOutput3 = GetElementPtrOperation::create(ctxVar.inner, { zero, two }, structType);
1941 auto & loadNode3 = LoadNonVolatileOperation::CreateNode(*gepOutput3, {}, bits32Type, 4);
1943 auto gepOutput4 = GetElementPtrOperation::create(ctxVar.inner, { four }, bits8Type);
1944 auto & loadNode4 = LoadNonVolatileOperation::CreateNode(*gepOutput4, {}, bits32Type, 4);
1946 auto & loadNode5 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits64Type, 4);
1948 auto gepOutput6 = GetElementPtrOperation::create(ctxVar.inner, { zero, four }, structType);
1949 auto & loadNode6 = LoadNonVolatileOperation::CreateNode(*gepOutput6, {}, pointerType, 4);
1951 lambdaNode.finalize({ &LoadOperation::LoadedValueOutput(loadNode0),
1952 &LoadOperation::LoadedValueOutput(loadNode1),
1953 &LoadOperation::LoadedValueOutput(loadNode2),
1954 &LoadOperation::LoadedValueOutput(loadNode3),
1955 &LoadOperation::LoadedValueOutput(loadNode4),
1956 &LoadOperation::LoadedValueOutput(loadNode5),
1957 &LoadOperation::LoadedValueOutput(loadNode6) });
1963 auto [intNode0, intOperation0] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1964 *lambdaNode.GetFunctionResults()[0]->origin());
1965 EXPECT_NE(intOperation0,
nullptr);
1966 EXPECT_EQ(intOperation0->Representation().to_uint(), 0u);
1968 auto [intNode1, intOperation1] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1969 *lambdaNode.GetFunctionResults()[1]->origin());
1970 EXPECT_NE(intOperation1,
nullptr);
1971 EXPECT_EQ(intOperation1->Representation().to_uint(), 0u);
1973 auto [intNode2, intOperation2] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1974 *lambdaNode.GetFunctionResults()[2]->origin());
1975 EXPECT_NE(intOperation2,
nullptr);
1976 EXPECT_EQ(intOperation2->Representation().to_uint(), 0u);
1978 auto [intNode3, intOperation3] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1979 *lambdaNode.GetFunctionResults()[3]->origin());
1980 EXPECT_NE(intOperation3,
nullptr);
1981 EXPECT_EQ(intOperation3->Representation().to_uint(), 2u);
1983 auto [intNode4, intOperation4] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1984 *lambdaNode.GetFunctionResults()[4]->origin());
1985 EXPECT_NE(intOperation4,
nullptr);
1986 EXPECT_EQ(intOperation4->Representation().to_uint(), 1u);
1990 auto [loadNode, loadOperation] = TryGetSimpleNodeAndOptionalOp<LoadNonVolatileOperation>(
1991 *lambdaNode.GetFunctionResults()[5]->origin());
1992 EXPECT_NE(loadOperation,
nullptr);
1994 auto [intNode5, intOperation5] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1995 *lambdaNode.GetFunctionResults()[5]->origin());
1996 EXPECT_NE(intOperation5,
nullptr);
1997 EXPECT_EQ(intOperation5->Representation().to_uint(), 0x0000000100000000u);
2001 auto [fnToPtrNode, fnToPtrOperation] = TryGetSimpleNodeAndOptionalOp<FunctionToPointerOperation>(
2002 *lambdaNode.GetFunctionResults()[6]->origin());
2003 EXPECT_NE(fnToPtrOperation,
nullptr);
2006TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithConstantArray)
2013 auto & graph = rvsdgModule.
Rvsdg();
2014 const auto pointerType = PointerType::Create();
2015 const auto bits8Type = BitType::Create(8);
2016 const auto bits32Type = BitType::Create(32);
2017 const auto bits64Type = BitType::Create(64);
2018 const auto arrayType = ArrayType::Create(bits32Type, 3);
2019 const auto functionType = FunctionType::Create(
2030 auto deltaNode = DeltaNode::Create(
2031 &graph.GetRootRegion(),
2032 DeltaOperation::Create(arrayType,
true, pointerType));
2033 auto & zeroNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 0);
2034 auto & oneNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 1);
2035 auto & twoNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 2);
2036 auto constantDataArrayResult =
2037 ConstantArrayOperation::Create({ zeroNode.output(0), oneNode.output(0), twoNode.output(0) });
2038 auto & deltaOutput = deltaNode->finalize(constantDataArrayResult);
2040 auto & lambdaNode = *LambdaNode::Create(
2041 graph.GetRootRegion(),
2042 LlvmLambdaOperation::Create(functionType,
"func", Linkage::internalLinkage));
2043 auto ctxVar = lambdaNode.AddContextVar(deltaOutput);
2045 auto zero = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 0).output(0);
2046 auto two = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2).output(0);
2047 auto four = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 4).output(0);
2049 auto & loadNode0 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits32Type, 4);
2051 auto gepOutput1 = GetElementPtrOperation::create(ctxVar.inner, { zero }, arrayType);
2052 auto & loadNode1 = LoadNonVolatileOperation::CreateNode(*gepOutput1, {}, bits32Type, 4);
2054 auto gepOutput2 = GetElementPtrOperation::create(ctxVar.inner, { zero, zero }, arrayType);
2055 auto & loadNode2 = LoadNonVolatileOperation::CreateNode(*gepOutput2, {}, bits32Type, 4);
2057 auto gepOutput3 = GetElementPtrOperation::create(ctxVar.inner, { zero, two }, arrayType);
2058 auto & loadNode3 = LoadNonVolatileOperation::CreateNode(*gepOutput3, {}, bits32Type, 4);
2060 auto gepOutput4 = GetElementPtrOperation::create(ctxVar.inner, { four }, bits8Type);
2061 auto & loadNode4 = LoadNonVolatileOperation::CreateNode(*gepOutput4, {}, bits32Type, 4);
2063 auto & loadNode5 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits64Type, 4);
2065 lambdaNode.finalize({
2066 &LoadOperation::LoadedValueOutput(loadNode0),
2067 &LoadOperation::LoadedValueOutput(loadNode1),
2068 &LoadOperation::LoadedValueOutput(loadNode2),
2069 &LoadOperation::LoadedValueOutput(loadNode3),
2070 &LoadOperation::LoadedValueOutput(loadNode4),
2071 &LoadOperation::LoadedValueOutput(loadNode5),
2079 auto [intNode0, intOperation0] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2080 *lambdaNode.GetFunctionResults()[0]->origin());
2081 EXPECT_NE(intOperation0,
nullptr);
2082 EXPECT_EQ(intOperation0->Representation().to_uint(), 0);
2086 auto [intNode1, intOperation1] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2087 *lambdaNode.GetFunctionResults()[1]->origin());
2088 EXPECT_NE(intOperation1,
nullptr);
2089 EXPECT_EQ(intOperation1->Representation().to_uint(), 0);
2093 auto [intNode2, intOperation2] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2094 *lambdaNode.GetFunctionResults()[2]->origin());
2095 EXPECT_NE(intOperation2,
nullptr);
2096 EXPECT_EQ(intOperation2->Representation().to_uint(), 0);
2100 auto [intNode3, intOperation3] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2101 *lambdaNode.GetFunctionResults()[3]->origin());
2102 EXPECT_NE(intOperation3,
nullptr);
2103 EXPECT_EQ(intOperation3->Representation().to_uint(), 2);
2107 auto [intNode4, intOperation4] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2108 *lambdaNode.GetFunctionResults()[4]->origin());
2109 EXPECT_NE(intOperation4,
nullptr);
2110 EXPECT_EQ(intOperation4->Representation().to_uint(), 1);
2115 auto [loadNode, loadOperation] = TryGetSimpleNodeAndOptionalOp<LoadNonVolatileOperation>(
2116 *lambdaNode.GetFunctionResults()[5]->origin());
2117 EXPECT_NE(loadOperation,
nullptr);
2119 auto [intNode5, intOperation5] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2120 *lambdaNode.GetFunctionResults()[5]->origin());
2121 EXPECT_NE(intOperation5,
nullptr);
2122 EXPECT_EQ(intOperation5->Representation().to_uint(), 0x0000000100000000);
2171TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithConstantGep)
2184 auto & graph = rvsdgModule.
Rvsdg();
2186 const auto pointerType = PointerType::Create();
2187 const auto bits8Type = BitType::Create(8);
2188 const auto bits32Type = BitType::Create(32);
2189 const auto structType =
2190 StructType::CreateIdentified(
"struct.s", { bits32Type, bits32Type },
false);
2193 auto s0 = DeltaNode::Create(
2194 &graph.GetRootRegion(),
2195 DeltaOperation::Create(structType,
true, pointerType));
2196 auto & one = IntegerConstantOperation::Create(*s0->subregion(), 32, 1);
2197 auto & two = IntegerConstantOperation::Create(*s0->subregion(), 32, 2);
2198 auto & s0Value = ConstantStructOperation::Create(
2200 { one.output(0), two.output(0) },
2202 auto & s0Output = s0->finalize(&s0Value);
2205 auto v = DeltaNode::Create(
2206 &graph.GetRootRegion(),
2207 DeltaOperation::Create(pointerType,
true, pointerType));
2208 auto vContext = v->AddContextVar(s0Output);
2209 auto four = IntegerConstantOperation::Create(*v->subregion(), 64, 4).output(0);
2210 auto vValue = GetElementPtrOperation::create(vContext.inner, { four }, bits8Type);
2211 auto & vOutput = v->finalize(vValue);
2213 auto & lambdaNode = *LambdaNode::Create(
2214 graph.GetRootRegion(),
2215 LlvmLambdaOperation::Create(
2216 FunctionType::Create({}, { bits32Type }),
2218 Linkage::internalLinkage));
2219 auto vContextVar = lambdaNode.AddContextVar(vOutput);
2222 auto & pointerLoad = LoadNonVolatileOperation::CreateNode(*vContextVar.inner, {}, pointerType, 8);
2225 LoadNonVolatileOperation::CreateNode(*pointerLoad.output(0), {}, bits32Type, 4);
2226 lambdaNode.finalize({ &LoadOperation::LoadedValueOutput(valueLoad) });
2232 EXPECT_FALSE(Region::containsOperation<LoadNonVolatileOperation>(graph.GetRootRegion(),
true));
2234 auto [intNode, intOperation] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2235 *lambdaNode.GetFunctionResults()[0]->origin());
2236 EXPECT_NE(intNode,
nullptr);
2237 EXPECT_NE(intOperation,
nullptr);
2238 EXPECT_EQ(intOperation->Representation().to_uint(), 2u);