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);
511 const auto & traced1stRegionOrigin =
513 const auto loopVar2 = thetaNode.MapPreLoopVar(traced1stRegionOrigin);
514 EXPECT_EQ(loopVar.pre, loopVar2.pre);
517 EXPECT_EQ(constInputInteger, 40u);
520TEST(StoreValueForwardingTests, RouteAroundLoadLoop)
546 auto & graph = rvsdgModule.
Rvsdg();
547 const auto pointerType = PointerType::Create();
548 const auto bits32Type = rvsdg::BitType::Create(32);
549 const auto ioStateType = IOStateType::Create();
550 const auto memoryStateType = MemoryStateType::Create();
552 const auto funcType = rvsdg::FunctionType::Create(
553 { pointerType, ioStateType, memoryStateType },
554 { bits32Type, ioStateType, memoryStateType });
557 auto & lambdaNode = *rvsdg::LambdaNode::Create(
558 graph.GetRootRegion(),
559 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
561 auto & q = *lambdaNode.GetFunctionArguments()[0];
562 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
563 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
566 auto & constantForty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 40);
567 auto & storeQ40Node =
568 StoreNonVolatileOperation::CreateNode(q, *constantForty.output(0), { &mem0 }, 4);
569 auto & mem1 = *StoreOperation::MemoryStateOutputs(storeQ40Node).begin();
572 auto & thetaNode = *rvsdg::ThetaNode::create(lambdaNode.subregion());
573 auto qLoopVar = thetaNode.AddLoopVar(&q);
574 auto memLoopVar = thetaNode.AddLoopVar(&mem1);
575 auto undefL = UndefValueOperation::Create(*lambdaNode.subregion(), bits32Type);
576 auto lLoopVar = thetaNode.AddLoopVar(undefL);
578 auto & loadInLoopNode =
579 LoadNonVolatileOperation::CreateNode(*qLoopVar.pre, { memLoopVar.pre }, bits32Type, 4);
580 auto & l1 = LoadOperation::LoadedValueOutput(loadInLoopNode);
581 auto & mem3 = *LoadOperation::MemoryStateOutputs(loadInLoopNode).begin();
583 lLoopVar.post->divert_to(&l1);
584 memLoopVar.post->divert_to(&mem3);
587 auto & loadAfterLoopNode =
588 LoadNonVolatileOperation::CreateNode(q, { memLoopVar.output }, bits32Type, 4);
589 auto & l3 = LoadOperation::LoadedValueOutput(loadAfterLoopNode);
590 auto & mem5 = *LoadOperation::MemoryStateOutputs(loadAfterLoopNode).begin();
593 auto & addNode = rvsdg::CreateOpNode<IntegerAddOperation>({ lLoopVar.output, &l3 }, 32);
594 auto & add1 = *addNode.output(0);
597 lambdaNode.finalize({ &add1, &io0, &mem5 });
610 const auto & addLhsOrigin = *addNode.input(0)->origin();
611 const auto loopVar1 = thetaNode.MapOutputLoopVar(addLhsOrigin);
612 const auto loopVar2 = thetaNode.MapPreLoopVar(*loopVar1.post->origin());
613 EXPECT_TRUE(rvsdg::ThetaLoopVarIsInvariant(loopVar2));
614 EXPECT_EQ(tryGetConstantSignedInteger(*loopVar2.input->origin()), 40u);
617 const auto & addRhsOrigin = *addNode.input(1)->origin();
618 EXPECT_EQ(tryGetConstantSignedInteger(addRhsOrigin), 40u);
619 EXPECT_EQ(rvsdg::TryGetOwnerNode<rvsdg::ThetaNode>(addRhsOrigin),
nullptr);
622TEST(StoreValueForwardingTests, RouteUninitialized)
651 auto & graph = rvsdgModule.
Rvsdg();
652 const auto bits32Type = rvsdg::BitType::Create(32);
653 const auto ioStateType = IOStateType::Create();
654 const auto memoryStateType = MemoryStateType::Create();
655 const auto unitType = rvsdg::UnitType::Create();
657 const auto funcType = rvsdg::FunctionType::Create(
658 { ioStateType, memoryStateType },
659 { bits32Type, ioStateType, memoryStateType });
661 auto & lambdaNode = *rvsdg::LambdaNode::Create(
662 graph.GetRootRegion(),
663 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
665 auto & io0 = *lambdaNode.GetFunctionArguments()[0];
666 auto & mem0 = *lambdaNode.GetFunctionArguments()[1];
669 auto & constantOne = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 1);
670 auto allocaAOutputs = AllocaOperation::create(bits32Type, constantOne.output(0), 4);
673 auto & predicate = rvsdg::ControlConstantOperation::create(*lambdaNode.subregion(), 2, 0);
676 auto & gammaNode = rvsdg::GammaNode::Create(predicate, 2, { unitType, unitType });
677 auto aEntryVar = gammaNode.AddEntryVar(allocaAOutputs[0]);
678 auto memEntryVar = gammaNode.AddEntryVar(allocaAOutputs[1]);
681 auto & gammaSubregion0 = *gammaNode.subregion(0);
682 auto & constantTwenty = IntegerConstantOperation::Create(gammaSubregion0, 32, 20);
683 auto & storeA20Node = StoreNonVolatileOperation::CreateNode(
684 *aEntryVar.branchArgument[0],
685 *constantTwenty.output(0),
686 { memEntryVar.branchArgument[0] },
688 auto & mem3 = *StoreOperation::MemoryStateOutputs(storeA20Node).begin();
691 auto memExitVar = gammaNode.AddExitVar({ &mem3, memEntryVar.branchArgument[1] });
694 auto & loadNode = LoadNonVolatileOperation::CreateNode(
696 { memExitVar.output },
699 auto & ld = LoadOperation::LoadedValueOutput(loadNode);
701 lambdaNode.finalize({ &ld, &io0, &mem0 });
707 const auto & resultOrigin = *lambdaNode.GetFunctionResults()[0]->origin();
708 EXPECT_NE(rvsdg::TryGetOwnerNode<rvsdg::GammaNode>(resultOrigin),
nullptr);
710 const auto exitVar = gammaNode.MapOutputExitVar(resultOrigin);
712 const auto [undefNode, undefOperation] =
713 rvsdg::TryGetSimpleNodeAndOptionalOp<UndefValueOperation>(*exitVar.branchResult[1]->origin());
714 EXPECT_TRUE(undefNode && undefOperation);
717TEST(StoreValueForwardingTests, GepInLoop)
752 auto & graph = rvsdgModule.
Rvsdg();
753 const auto pointerType = PointerType::Create();
754 const auto bits32Type = rvsdg::BitType::Create(32);
755 const auto intArrayType = ArrayType::Create(bits32Type, 4);
756 const auto ioStateType = IOStateType::Create();
757 const auto memoryStateType = MemoryStateType::Create();
759 const auto funcType = rvsdg::FunctionType::Create(
760 { ioStateType, memoryStateType },
761 { bits32Type, ioStateType, memoryStateType });
763 auto & lambdaNode = *rvsdg::LambdaNode::Create(
764 graph.GetRootRegion(),
765 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
767 auto & io0 = *lambdaNode.GetFunctionArguments()[0];
768 auto & mem0 = *lambdaNode.GetFunctionArguments()[1];
770 auto & constantZero = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 0);
771 auto & constantOne = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 1);
772 auto & constantTwo = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2);
773 auto & constantThree = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 3);
774 auto & constantTwenty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 20);
775 auto & constantThirty = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 30);
778 auto allocaAOutputs = AllocaOperation::create(intArrayType, constantOne.output(0), 4);
781 auto a2 = GetElementPtrOperation::create(
783 { constantZero.output(0), constantTwo.output(0) },
785 auto a3 = GetElementPtrOperation::create(
787 { constantZero.output(0), constantThree.output(0) },
791 auto & storeA220Node = StoreNonVolatileOperation::CreateNode(
793 *constantTwenty.output(0),
794 { allocaAOutputs[1] },
796 auto & mem1 = *StoreOperation::MemoryStateOutputs(storeA220Node).begin();
797 auto & storeA330Node =
798 StoreNonVolatileOperation::CreateNode(*a3, *constantThirty.output(0), { &mem1 }, 4);
799 auto & mem2 = *StoreOperation::MemoryStateOutputs(storeA330Node).begin();
802 auto & thetaNode = *rvsdg::ThetaNode::create(lambdaNode.subregion());
803 auto aLoopVar = thetaNode.AddLoopVar(allocaAOutputs[0]);
804 auto a2LoopVar = thetaNode.AddLoopVar(a2);
805 auto memLoopVar = thetaNode.AddLoopVar(&mem2);
808 auto & loadInLoopNode =
809 LoadNonVolatileOperation::CreateNode(*a2LoopVar.pre, { memLoopVar.pre }, bits32Type, 4);
810 auto & loadedValue = LoadOperation::LoadedValueOutput(loadInLoopNode);
811 auto & mem3 = *LoadOperation::MemoryStateOutputs(loadInLoopNode).begin();
814 auto & constantOneInLoop = IntegerConstantOperation::Create(*thetaNode.subregion(), 32, 1);
816 GetElementPtrOperation::create(aLoopVar.pre, { constantOneInLoop.output(0) }, bits32Type);
817 auto a22 = GetElementPtrOperation::create(a1, { constantOneInLoop.output(0) }, bits32Type);
820 auto & addLoadedOneNode =
821 rvsdg::CreateOpNode<IntegerAddOperation>({ &loadedValue, constantOneInLoop.output(0) }, 32);
822 auto & incrementedValue = *addLoadedOneNode.output(0);
823 auto & storeA22Node = StoreNonVolatileOperation::CreateNode(*a22, incrementedValue, { &mem3 }, 4);
824 auto & mem4 = *StoreOperation::MemoryStateOutputs(storeA22Node).begin();
827 auto & constantTen = IntegerConstantOperation::Create(*thetaNode.subregion(), 32, 10);
829 StoreNonVolatileOperation::CreateNode(*a1, *constantTen.output(0), { &mem4 }, 4);
830 auto & mem5 = *StoreOperation::MemoryStateOutputs(storeA1Node).begin();
832 memLoopVar.post->divert_to(&mem5);
835 auto & loadAfterLoopA2Node =
836 LoadNonVolatileOperation::CreateNode(*a2, { memLoopVar.output }, bits32Type, 4);
837 auto & loadedA2 = LoadOperation::LoadedValueOutput(loadAfterLoopA2Node);
838 auto & mem6 = *LoadOperation::MemoryStateOutputs(loadAfterLoopA2Node).begin();
839 auto & loadAfterLoopA3Node = LoadNonVolatileOperation::CreateNode(*a3, { &mem6 }, bits32Type, 4);
840 auto & loadedA3 = LoadOperation::LoadedValueOutput(loadAfterLoopA3Node);
841 auto & addResultNode = rvsdg::CreateOpNode<IntegerAddOperation>({ &loadedA2, &loadedA3 }, 32);
842 auto & resultValue = *addResultNode.output(0);
844 lambdaNode.finalize({ &resultValue, &io0, &mem0 });
846 std::cout << rvsdg::view(&graph.GetRootRegion()) << std::endl;
851 std::cout << rvsdg::view(&graph.GetRootRegion()) << std::endl;
857 const auto & loadedInLoopOrigin = *addLoadedOneNode.input(0)->origin();
858 const auto loadedLoopVar = thetaNode.MapPreLoopVar(loadedInLoopOrigin);
860 EXPECT_EQ(loadedLoopVar.post->origin(), addLoadedOneNode.output(0));
863 const auto & addLhsOrigin = *addResultNode.input(0)->origin();
864 const auto a2ResultLoopVar = thetaNode.MapOutputLoopVar(addLhsOrigin);
865 EXPECT_EQ(a2ResultLoopVar.post->origin(), addLoadedOneNode.output(0));
869 const auto & addRhsOrigin = *addResultNode.input(1)->origin();
870 EXPECT_EQ(&addRhsOrigin, constantThirty.output(0));
873TEST(StoreValueForwardingTests, LoadForwarding)
892 auto & graph = rvsdgModule.
Rvsdg();
893 const auto pointerType = PointerType::Create();
894 const auto bits32Type = rvsdg::BitType::Create(32);
895 const auto ioStateType = IOStateType::Create();
896 const auto memoryStateType = MemoryStateType::Create();
898 const auto funcType = rvsdg::FunctionType::Create(
899 { pointerType, ioStateType, memoryStateType },
900 { bits32Type, ioStateType, memoryStateType });
902 auto & lambdaNode = *rvsdg::LambdaNode::Create(
903 graph.GetRootRegion(),
904 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
906 auto & p = *lambdaNode.GetFunctionArguments()[0];
907 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
908 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
910 auto & load1Node = LoadNonVolatileOperation::CreateNode(p, { &mem0 }, bits32Type, 4);
911 auto & l1 = LoadOperation::LoadedValueOutput(load1Node);
912 auto & mem1 = *LoadOperation::MemoryStateOutputs(load1Node).begin();
914 auto & load2Node = LoadNonVolatileOperation::CreateNode(p, { &mem1 }, bits32Type, 4);
915 auto & l2 = LoadOperation::LoadedValueOutput(load2Node);
916 auto & mem2 = *LoadOperation::MemoryStateOutputs(load2Node).begin();
918 auto & addNode = rvsdg::CreateOpNode<IntegerAddOperation>({ &l1, &l2 }, 32);
919 auto & add0 = *addNode.output(0);
921 lambdaNode.finalize({ &add0, &io0, &mem2 });
927 size_t loadCount = 0;
928 for (
auto & node : lambdaNode.subregion()->Nodes())
930 if (is<LoadOperation>(&node))
933 EXPECT_EQ(loadCount, 1u);
937 EXPECT_EQ(&addLhsOrigin, &l1);
938 EXPECT_EQ(&addRhsOrigin, &l1);
940 const auto & memoryResultOrigin =
942 EXPECT_EQ(&memoryResultOrigin, &mem1);
945TEST(StoreValueForwardingTests, LoadForwardingIntoTheta)
971 auto & graph = rvsdgModule.
Rvsdg();
972 const auto pointerType = PointerType::Create();
973 const auto bits32Type = rvsdg::BitType::Create(32);
974 const auto ioStateType = IOStateType::Create();
975 const auto memoryStateType = MemoryStateType::Create();
977 const auto funcType = rvsdg::FunctionType::Create(
978 { pointerType, ioStateType, memoryStateType },
979 { bits32Type, ioStateType, memoryStateType });
981 auto & lambdaNode = *rvsdg::LambdaNode::Create(
982 graph.GetRootRegion(),
983 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
985 auto & p = *lambdaNode.GetFunctionArguments()[0];
986 auto & io0 = *lambdaNode.GetFunctionArguments()[1];
987 auto & mem0 = *lambdaNode.GetFunctionArguments()[2];
989 auto & load1Node = LoadNonVolatileOperation::CreateNode(p, { &mem0 }, bits32Type, 4);
990 auto & l1 = LoadOperation::LoadedValueOutput(load1Node);
991 auto & mem1 = *LoadOperation::MemoryStateOutputs(load1Node).begin();
993 auto & thetaNode = *rvsdg::ThetaNode::create(lambdaNode.subregion());
994 auto pLoopVar = thetaNode.AddLoopVar(&p);
995 auto sumLoopVar = thetaNode.AddLoopVar(&l1);
996 auto memLoopVar = thetaNode.AddLoopVar(&mem1);
999 LoadNonVolatileOperation::CreateNode(*pLoopVar.pre, { memLoopVar.pre }, bits32Type, 4);
1000 auto & l2 = LoadOperation::LoadedValueOutput(load2Node);
1001 auto & mem3 = *LoadOperation::MemoryStateOutputs(load2Node).begin();
1003 auto & addNode = rvsdg::CreateOpNode<IntegerAddOperation>({ sumLoopVar.pre, &l2 }, 32);
1004 auto & sum2 = *addNode.output(0);
1006 auto & constant100 = IntegerConstantOperation::Create(*thetaNode.subregion(), 32, 100);
1007 auto & sltNode = rvsdg::CreateOpNode<IntegerSltOperation>({ &sum2, constant100.output(0) }, 32);
1008 const auto predicate = rvsdg::MatchOperation::Create(*sltNode.output(0), { { 1, 1 } }, 0, 2);
1010 thetaNode.set_predicate(predicate);
1011 sumLoopVar.post->divert_to(&sum2);
1012 memLoopVar.post->divert_to(&mem3);
1014 lambdaNode.finalize({ sumLoopVar.output, &io0, memLoopVar.output });
1020 size_t lambdaLoadCount = 0;
1021 for (
auto & node : lambdaNode.subregion()->Nodes())
1023 if (is<LoadOperation>(&node))
1026 EXPECT_EQ(lambdaLoadCount, 1u);
1028 size_t thetaLoadCount = 0;
1029 for (
auto & node : thetaNode.subregion()->Nodes())
1031 if (is<LoadOperation>(&node))
1034 EXPECT_EQ(thetaLoadCount, 0u);
1037 EXPECT_EQ(&addLhsOrigin, sumLoopVar.pre);
1039 const auto & addRhsOrigin = *addNode.input(1)->origin();
1040 const auto forwardedLoopVar = thetaNode.MapPreLoopVar(addRhsOrigin);
1041 EXPECT_TRUE(rvsdg::ThetaLoopVarIsInvariant(forwardedLoopVar));
1042 EXPECT_EQ(forwardedLoopVar.input->origin(), &l1);
1045 const auto & memoryResultOrigin =
1047 EXPECT_EQ(&memoryResultOrigin, &mem1);
1050TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithIntegerConstant)
1057 auto & graph = rvsdgModule.
Rvsdg();
1059 const auto pointerType = PointerType::Create();
1060 const auto bits8Type = BitType::Create(8);
1061 const auto bits32Type = BitType::Create(32);
1062 const auto functionType = FunctionType::Create(
1069 auto deltaNode = DeltaNode::Create(
1070 &graph.GetRootRegion(),
1071 DeltaOperation::Create(bits32Type,
true, pointerType));
1072 auto & four = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 4);
1073 auto & deltaOutput = deltaNode->finalize(four.output(0));
1075 auto & lambdaNode = *LambdaNode::Create(
1076 graph.GetRootRegion(),
1077 LlvmLambdaOperation::Create(functionType,
"func", Linkage::internalLinkage));
1078 auto ctxVar = lambdaNode.AddContextVar(deltaOutput);
1080 auto & load32Node = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits32Type, 4);
1081 auto & load8Node = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits8Type, 4);
1083 lambdaNode.finalize({ &LoadOperation::LoadedValueOutput(load32Node),
1084 &LoadOperation::LoadedValueOutput(load8Node) });
1091 auto [intNode0, intOperation0] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1092 *lambdaNode.GetFunctionResults()[0]->origin());
1093 EXPECT_NE(intOperation0,
nullptr);
1094 EXPECT_EQ(intOperation0->Representation().nbits(), 32u);
1095 EXPECT_EQ(intOperation0->Representation().to_uint(), 4u);
1099 auto [truncNode, truncOperation] = TryGetSimpleNodeAndOptionalOp<TruncOperation>(
1100 *lambdaNode.GetFunctionResults()[1]->origin());
1101 EXPECT_NE(truncOperation,
nullptr);
1103 auto [intNode1, intOperation1] =
1104 TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(*truncNode->input(0)->origin());
1105 EXPECT_NE(intOperation1,
nullptr);
1106 EXPECT_EQ(intOperation1->Representation().nbits(), 32u);
1107 EXPECT_EQ(intOperation1->Representation().to_uint(), 4u);
1111TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithAggregateZeroConstant)
1118 auto & graph = rvsdgModule.
Rvsdg();
1120 const auto pointerType = PointerType::Create();
1121 const auto bits32Type = BitType::Create(32);
1122 const auto fixedVectorType = FixedVectorType::Create(bits32Type, 4);
1123 const auto floatType = FloatingPointType::Create(fpsize::flt);
1124 const auto doubleType = FloatingPointType::Create(fpsize::dbl);
1125 const auto structType = StructType::CreateIdentified(
1127 { bits32Type, pointerType, fixedVectorType, floatType, doubleType },
1129 const auto functionType =
1130 FunctionType::Create({}, { bits32Type, pointerType, fixedVectorType, floatType, doubleType });
1132 auto deltaNode = DeltaNode::Create(
1133 &graph.GetRootRegion(),
1134 DeltaOperation::Create(structType,
true, pointerType));
1135 auto aggregateZero = ConstantAggregateZeroOperation::Create(*deltaNode->subregion(), structType);
1136 auto & deltaOutput = deltaNode->finalize(aggregateZero);
1138 auto & lambdaNode = *LambdaNode::Create(
1139 graph.GetRootRegion(),
1140 LlvmLambdaOperation::Create(functionType,
"func", Linkage::internalLinkage));
1141 auto ctxVar = lambdaNode.AddContextVar(deltaOutput);
1143 auto & zeroNode = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 0);
1144 auto & oneNode = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 1);
1145 auto & twoNode = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2);
1146 auto & threeNode = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 3);
1147 auto & fourNode = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 4);
1149 auto & gep0Node = GetElementPtrOperation::createNode(
1151 { zeroNode.output(0), zeroNode.output(0) },
1153 auto & load32Node = LoadNonVolatileOperation::CreateNode(*gep0Node.output(0), {}, bits32Type, 4);
1155 auto & gep1Node = GetElementPtrOperation::createNode(
1157 { zeroNode.output(0), oneNode.output(0) },
1159 auto & loadPtrNode =
1160 LoadNonVolatileOperation::CreateNode(*gep1Node.output(0), {}, pointerType, 4);
1162 auto & gep2Node = GetElementPtrOperation::createNode(
1164 { zeroNode.output(0), twoNode.output(0) },
1166 auto & loadV32Node =
1167 LoadNonVolatileOperation::CreateNode(*gep2Node.output(0), {}, fixedVectorType, 4);
1169 auto & gepFloatNode = GetElementPtrOperation::createNode(
1171 { zeroNode.output(0), threeNode.output(0) },
1173 auto & loadFloatNode =
1174 LoadNonVolatileOperation::CreateNode(*gepFloatNode.output(0), {}, floatType, 4);
1176 auto & gepDoubleNode = GetElementPtrOperation::createNode(
1178 { zeroNode.output(0), fourNode.output(0) },
1180 auto & loadDoubleNode =
1181 LoadNonVolatileOperation::CreateNode(*gepDoubleNode.output(0), {}, doubleType, 8);
1183 lambdaNode.finalize({
1184 &LoadOperation::LoadedValueOutput(load32Node),
1185 &LoadOperation::LoadedValueOutput(loadPtrNode),
1186 &LoadOperation::LoadedValueOutput(loadV32Node),
1187 &LoadOperation::LoadedValueOutput(loadFloatNode),
1188 &LoadOperation::LoadedValueOutput(loadDoubleNode),
1196 EXPECT_FALSE(Region::containsOperation<LoadNonVolatileOperation>(graph.GetRootRegion(),
true));
1199 auto [intNode, intOperation] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1200 *lambdaNode.GetFunctionResults()[0]->origin());
1201 EXPECT_NE(intOperation,
nullptr);
1202 EXPECT_EQ(intOperation->Representation().to_uint(), 0u);
1206 auto [nullPtrNode, nullPtrOperation] =
1207 TryGetSimpleNodeAndOptionalOp<ConstantPointerNullOperation>(
1208 *lambdaNode.GetFunctionResults()[1]->origin());
1209 EXPECT_NE(nullPtrOperation,
nullptr);
1213 auto [aggZeroNode, aggZeroOperation] =
1214 TryGetSimpleNodeAndOptionalOp<ConstantAggregateZeroOperation>(
1215 *lambdaNode.GetFunctionResults()[2]->origin());
1216 EXPECT_NE(aggZeroOperation,
nullptr);
1220 auto [floatNode, floatOperation] =
1221 TryGetSimpleNodeAndOptionalOp<ConstantFP>(*lambdaNode.GetFunctionResults()[3]->origin());
1222 EXPECT_NE(floatOperation,
nullptr);
1223 EXPECT_EQ(&floatOperation->constant().getSemantics(), &llvm::APFloat::IEEEsingle());
1224 EXPECT_TRUE(floatOperation->constant().isZero());
1228 auto [doubleNode, doubleOperation] =
1229 TryGetSimpleNodeAndOptionalOp<ConstantFP>(*lambdaNode.GetFunctionResults()[4]->origin());
1230 EXPECT_NE(doubleOperation,
nullptr);
1231 EXPECT_EQ(&doubleOperation->constant().getSemantics(), &llvm::APFloat::IEEEdouble());
1232 EXPECT_TRUE(doubleOperation->constant().isZero());
1236TEST(StoreValueForwardingTests, LoadForwardingFromDeltaCtxVar)
1243 auto & graph = rvsdgModule.
Rvsdg();
1244 const auto pointerType = PointerType::Create();
1245 const auto bits32Type = BitType::Create(32);
1246 const auto functionType = FunctionType::Create(
1252 auto deltaNode1 = DeltaNode::Create(
1253 &graph.GetRootRegion(),
1254 DeltaOperation::Create(bits32Type,
true, pointerType));
1255 auto & four = IntegerConstantOperation::Create(*deltaNode1->subregion(), 32, 4);
1256 auto & deltaOutput1 = deltaNode1->finalize(four.output(0));
1258 auto deltaNode2 = DeltaNode::Create(
1259 &graph.GetRootRegion(),
1260 DeltaOperation::Create(pointerType,
true, pointerType));
1261 auto deltaCtxVar = deltaNode2->AddContextVar(deltaOutput1);
1262 auto & deltaOutput2 = deltaNode2->finalize(deltaCtxVar.inner);
1264 auto & lambdaNode = *LambdaNode::Create(
1265 graph.GetRootRegion(),
1266 LlvmLambdaOperation::Create(functionType,
"func", Linkage::internalLinkage));
1267 auto ctxVar = lambdaNode.AddContextVar(deltaOutput2);
1269 auto & loadNode = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, pointerType, 4);
1271 lambdaNode.finalize({ &LoadOperation::LoadedValueOutput(loadNode) });
1278 EXPECT_FALSE(Region::containsOperation<LoadNonVolatileOperation>(graph.GetRootRegion(),
true));
1280 EXPECT_EQ(deltaOutput1.nusers(), 2u);
1363TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithConstantDataArray)
1370 auto & graph = rvsdgModule.
Rvsdg();
1371 const auto pointerType = PointerType::Create();
1372 const auto bits8Type = BitType::Create(8);
1373 const auto bits32Type = BitType::Create(32);
1374 const auto bits64Type = BitType::Create(64);
1375 const auto arrayType = ArrayType::Create(bits32Type, 3);
1376 const auto functionType = FunctionType::Create(
1387 auto deltaNode = DeltaNode::Create(
1388 &graph.GetRootRegion(),
1389 DeltaOperation::Create(arrayType,
true, pointerType));
1390 auto & zeroNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 0);
1391 auto & oneNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 1);
1392 auto & twoNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 2);
1393 auto constantDataArrayResult = ConstantDataArrayOperation::Create(
1394 { zeroNode.output(0), oneNode.output(0), twoNode.output(0) });
1395 auto & deltaOutput = deltaNode->finalize(constantDataArrayResult);
1397 auto & lambdaNode = *LambdaNode::Create(
1398 graph.GetRootRegion(),
1399 LlvmLambdaOperation::Create(functionType,
"func", Linkage::internalLinkage));
1400 auto ctxVar = lambdaNode.AddContextVar(deltaOutput);
1402 auto zero = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 0).output(0);
1403 auto two = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2).output(0);
1404 auto four = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 4).output(0);
1406 auto & loadNode0 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits32Type, 4);
1408 auto gepOutput1 = GetElementPtrOperation::create(ctxVar.inner, { zero }, bits32Type);
1409 auto & loadNode1 = LoadNonVolatileOperation::CreateNode(*gepOutput1, {}, bits32Type, 4);
1411 auto gepOutput2 = GetElementPtrOperation::create(ctxVar.inner, { zero, zero }, arrayType);
1412 auto & loadNode2 = LoadNonVolatileOperation::CreateNode(*gepOutput2, {}, bits32Type, 4);
1414 auto gepOutput3 = GetElementPtrOperation::create(ctxVar.inner, { zero, two }, arrayType);
1415 auto & loadNode3 = LoadNonVolatileOperation::CreateNode(*gepOutput3, {}, bits32Type, 4);
1417 auto gepOutput4 = GetElementPtrOperation::create(ctxVar.inner, { four }, bits8Type);
1418 auto & loadNode4 = LoadNonVolatileOperation::CreateNode(*gepOutput4, {}, bits32Type, 4);
1420 auto & loadNode5 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits64Type, 4);
1422 lambdaNode.finalize({
1423 &LoadOperation::LoadedValueOutput(loadNode0),
1424 &LoadOperation::LoadedValueOutput(loadNode1),
1425 &LoadOperation::LoadedValueOutput(loadNode2),
1426 &LoadOperation::LoadedValueOutput(loadNode3),
1427 &LoadOperation::LoadedValueOutput(loadNode4),
1428 &LoadOperation::LoadedValueOutput(loadNode5),
1435 auto [intNode0, intOperation0] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1436 *lambdaNode.GetFunctionResults()[0]->origin());
1437 EXPECT_NE(intOperation0,
nullptr);
1438 EXPECT_EQ(intOperation0->Representation().to_uint(), 0u);
1440 auto [intNode1, intOperation1] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1441 *lambdaNode.GetFunctionResults()[1]->origin());
1442 EXPECT_NE(intOperation1,
nullptr);
1443 EXPECT_EQ(intOperation1->Representation().to_uint(), 0u);
1445 auto [intNode2, intOperation2] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1446 *lambdaNode.GetFunctionResults()[2]->origin());
1447 EXPECT_NE(intOperation2,
nullptr);
1448 EXPECT_EQ(intOperation2->Representation().to_uint(), 0u);
1450 auto [intNode3, intOperation3] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1451 *lambdaNode.GetFunctionResults()[3]->origin());
1452 EXPECT_NE(intOperation3,
nullptr);
1453 EXPECT_EQ(intOperation3->Representation().to_uint(), 2u);
1455 auto [intNode4, intOperation4] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1456 *lambdaNode.GetFunctionResults()[4]->origin());
1457 EXPECT_NE(intOperation4,
nullptr);
1458 EXPECT_EQ(intOperation4->Representation().to_uint(), 1u);
1462 auto [loadNode, loadOperation] = TryGetSimpleNodeAndOptionalOp<LoadNonVolatileOperation>(
1463 *lambdaNode.GetFunctionResults()[5]->origin());
1464 EXPECT_NE(loadOperation,
nullptr);
1466 auto [intNode5, intOperation5] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1467 *lambdaNode.GetFunctionResults()[5]->origin());
1468 EXPECT_NE(intOperation5,
nullptr);
1469 EXPECT_EQ(intOperation5->Representation().to_uint(), 0x0000000100000000u);
1474TEST(StoreValueForwardingTests, RegionPredicatedValueForwarding)
1476 using namespace jlm;
1513 auto & graph = rvsdgModule.
Rvsdg();
1514 const auto pointerType = PointerType::Create();
1515 const auto bit32Type = rvsdg::BitType::Create(32);
1516 const auto memoryStateType = MemoryStateType::Create();
1518 const auto funcType =
1519 rvsdg::FunctionType::Create({ pointerType, memoryStateType }, { bit32Type, memoryStateType });
1521 auto & lambdaNode = *rvsdg::LambdaNode::Create(
1522 graph.GetRootRegion(),
1523 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
1525 auto & p = *lambdaNode.GetFunctionArguments()[0];
1526 auto & mem0 = *lambdaNode.GetFunctionArguments()[1];
1529 auto & ctrlZero = rvsdg::ControlConstantOperation::create(*lambdaNode.subregion(), 2, 0);
1530 auto & gamma1 = *rvsdg::GammaNode::create(&ctrlZero, 2);
1532 auto gamma1PEntry = gamma1.AddEntryVar(&p);
1533 auto gamma1MemEntr = gamma1.AddEntryVar(&mem0);
1536 auto & constantForty = IntegerConstantOperation::Create(*gamma1.subregion(0), 32, 40);
1537 auto & storeP40Node = StoreNonVolatileOperation::CreateNode(
1538 *gamma1PEntry.branchArgument[0],
1539 *constantForty.output(0),
1540 { gamma1MemEntr.branchArgument[0] },
1542 auto & gamma1LeftMem = *StoreOperation::MemoryStateOutputs(storeP40Node).begin();
1543 auto & gamma1LeftCtrl = rvsdg::ControlConstantOperation::create(*gamma1.subregion(0), 2, 0);
1546 auto & gamma1RightCtrl = rvsdg::ControlConstantOperation::create(*gamma1.subregion(1), 2, 1);
1549 auto gamma1CtrlExit = gamma1.AddExitVar({ &gamma1LeftCtrl, &gamma1RightCtrl });
1550 auto gamma1MemExit = gamma1.AddExitVar({ &gamma1LeftMem, gamma1MemEntr.branchArgument[1] });
1553 auto & gamma2 = *rvsdg::GammaNode::create(gamma1CtrlExit.output, 2);
1555 auto gamma2PEntry = gamma2.AddEntryVar(&p);
1556 auto gamma2MemEntry = gamma2.AddEntryVar(gamma1MemExit.output);
1559 auto & loadPLeft = LoadNonVolatileOperation::CreateNode(
1560 *gamma2PEntry.branchArgument[0],
1561 { gamma2MemEntry.branchArgument[0] },
1564 auto & loadedPLeft = LoadNonVolatileOperation::LoadedValueOutput(loadPLeft);
1565 auto & memLeft = *LoadNonVolatileOperation::MemoryStateOutputs(loadPLeft).begin();
1568 auto & loadPRight = LoadNonVolatileOperation::CreateNode(
1569 *gamma2PEntry.branchArgument[1],
1570 { gamma2MemEntry.branchArgument[1] },
1573 auto & loadedPRight = LoadNonVolatileOperation::LoadedValueOutput(loadPRight);
1574 auto & memRight = *LoadNonVolatileOperation::MemoryStateOutputs(loadPRight).begin();
1577 auto gamma2ExitLoadedP = gamma2.AddExitVar({ &loadedPLeft, &loadedPRight });
1578 auto gamma2ExitMem = gamma2.AddExitVar({ &memLeft, &memRight });
1581 lambdaNode.finalize({ gamma2ExitLoadedP.output, gamma2ExitMem.output });
1590 const auto & leftPOrigin = *gamma2ExitLoadedP.branchResult[0]->origin();
1593 auto gamma = rvsdg::TryGetOwnerNode<rvsdg::GammaNode>(tracedLeftPOrigin);
1594 ASSERT_EQ(gamma, &gamma1);
1596 auto exitVarP = gamma->MapOutputExitVar(tracedLeftPOrigin);
1598 auto & leftG1Origin = *exitVarP.branchResult[0]->origin();
1599 ASSERT_TRUE(rvsdg::IsOwnerNodeOperation<IntegerConstantOperation>(leftG1Origin));
1603 auto & rightG1Origin = *exitVarP.branchResult[1]->origin();
1604 ASSERT_TRUE(rvsdg::IsOwnerNodeOperation<UndefValueOperation>(rightG1Origin));
1607 const auto & rightPOrigin = *gamma2ExitLoadedP.branchResult[1]->origin();
1608 ASSERT_TRUE(rvsdg::IsOwnerNodeOperation<LoadNonVolatileOperation>(rightPOrigin));
1611TEST(StoreValueForwardingTests, LoadForwardingFromLoopExiting)
1613 using namespace jlm;
1683 auto & graph = rvsdgModule.
Rvsdg();
1684 const auto pointerType = PointerType::Create();
1685 const auto bits32Type = rvsdg::BitType::Create(32);
1686 const auto ioStateType = IOStateType::Create();
1687 const auto memoryStateType = MemoryStateType::Create();
1688 const auto unitType = rvsdg::UnitType::Create();
1689 const auto controlType = rvsdg::ControlType::Create(2);
1692 const auto opaqueFuncType = rvsdg::FunctionType::Create(
1693 { ioStateType, memoryStateType },
1694 { ioStateType, memoryStateType });
1696 auto & opaqueImport = LlvmGraphImport::createFunctionImport(
1700 Linkage::externalLinkage,
1701 CallingConvention::Default);
1704 const auto funcType = rvsdg::FunctionType::Create(
1705 { pointerType, pointerType, ioStateType, memoryStateType },
1706 { bits32Type, ioStateType, memoryStateType });
1708 auto & lambdaNode = *rvsdg::LambdaNode::Create(
1709 graph.GetRootRegion(),
1710 LlvmLambdaOperation::Create(funcType,
"func", Linkage::internalLinkage));
1712 auto & p = *lambdaNode.GetFunctionArguments()[0];
1713 auto & q = *lambdaNode.GetFunctionArguments()[1];
1714 auto & io0 = *lambdaNode.GetFunctionArguments()[2];
1715 auto & mem0 = *lambdaNode.GetFunctionArguments()[3];
1718 auto opaqueCtxVar = lambdaNode.AddContextVar(opaqueImport);
1722 auto & thetaNode = *rvsdg::ThetaNode::create(lambdaNode.subregion());
1724 auto exitPredInit = UndefValueOperation::Create(*lambdaNode.subregion(), controlType);
1725 auto exitPredLoopVar = thetaNode.AddLoopVar(exitPredInit);
1726 auto pLoopVar = thetaNode.AddLoopVar(&p);
1727 auto qLoopVar = thetaNode.AddLoopVar(&q);
1728 auto memLoopVar = thetaNode.AddLoopVar(&mem0);
1729 auto ioLoopVar = thetaNode.AddLoopVar(&io0);
1730 auto opaqueLoopVar = thetaNode.AddLoopVar(opaqueCtxVar.inner);
1734 auto & callOpqNode = CallOperation::CreateNode(
1737 { ioLoopVar.pre, memLoopVar.pre });
1738 auto & io2 = CallOperation::GetIOStateOutput(callOpqNode);
1739 auto & mem2 = CallOperation::GetMemoryStateOutput(callOpqNode);
1742 auto & loadPNode = LoadNonVolatileOperation::CreateNode(*pLoopVar.pre, { &mem2 }, bits32Type, 4);
1743 auto & pLoad = LoadOperation::LoadedValueOutput(loadPNode);
1744 auto & mem3 = *LoadOperation::MemoryStateOutputs(loadPNode).begin();
1747 auto & constantZero = IntegerConstantOperation::Create(*thetaNode.subregion(), 32, 0);
1750 auto & neqCondNode =
1751 rvsdg::CreateOpNode<IntegerNeOperation>({ &pLoad, constantZero.output(0) }, 32);
1752 auto & gamma1Cond = *neqCondNode.output(0);
1755 const auto matchMapping = std::unordered_map<uint64_t, uint64_t>{ { 1, 1 } };
1756 auto & gamma1PredNode =
1757 rvsdg::CreateOpNode<rvsdg::MatchOperation>({ &gamma1Cond }, 1, matchMapping, 0, 2);
1758 auto & gamma1Pred = *gamma1PredNode.output(0);
1762 auto & outerGammaNode = rvsdg::GammaNode::Create(gamma1Pred, 2, { unitType, unitType });
1763 auto qEntryVar = outerGammaNode.AddEntryVar(qLoopVar.pre);
1764 auto memEntryVar = outerGammaNode.AddEntryVar(&mem3);
1769 auto & gammaSubregion0 = *outerGammaNode.subregion(0);
1770 auto & ctrlZeroOuter = rvsdg::ControlConstantOperation::create(gammaSubregion0, 2, 0);
1773 auto & gammaSubregion1 = *outerGammaNode.subregion(1);
1776 auto & loadQNode = LoadNonVolatileOperation::CreateNode(
1777 *qEntryVar.branchArgument[1],
1778 { memEntryVar.branchArgument[1] },
1781 auto & qLoad = LoadOperation::LoadedValueOutput(loadQNode);
1782 auto & mem6 = *LoadOperation::MemoryStateOutputs(loadQNode).begin();
1785 auto & constantZeroInner = IntegerConstantOperation::Create(gammaSubregion1, 32, 0);
1788 auto & neqCondInnerNode =
1789 rvsdg::CreateOpNode<IntegerNeOperation>({ &qLoad, constantZeroInner.output(0) }, 32);
1790 auto & gamma2Cond = *neqCondInnerNode.output(0);
1793 auto & gamma2PredNode =
1794 rvsdg::CreateOpNode<rvsdg::MatchOperation>({ &gamma2Cond }, 1, matchMapping, 0, 2);
1795 auto & gamma2Pred = *gamma2PredNode.output(0);
1800 auto & innerGammaNode = rvsdg::GammaNode::Create(gamma2Pred, 2, {});
1803 auto & innerGammaBranch0 = *innerGammaNode.subregion(0);
1804 auto & ctrlZero1 = rvsdg::ControlConstantOperation::create(innerGammaBranch0, 2, 0);
1805 auto & ctrlOne1 = rvsdg::ControlConstantOperation::create(innerGammaBranch0, 2, 1);
1807 auto & innerGammaBranch1 = *innerGammaNode.subregion(1);
1808 auto & ctrlOne2 = rvsdg::ControlConstantOperation::create(innerGammaBranch1, 2, 1);
1810 auto innerLoopPredExitVar = innerGammaNode.AddExitVar({ &ctrlZero1, &ctrlOne2 });
1811 auto innerExitPredExitVar = innerGammaNode.AddExitVar({ &ctrlOne1, &ctrlOne2 });
1814 auto outerLoopPredExitVar =
1815 outerGammaNode.AddExitVar({ &ctrlZeroOuter, innerLoopPredExitVar.output });
1816 auto outerExitPredExitVar =
1817 outerGammaNode.AddExitVar({ &ctrlZeroOuter, innerExitPredExitVar.output });
1821 auto memExitVar = outerGammaNode.AddExitVar({ memEntryVar.branchArgument[0], &mem6 });
1824 thetaNode.predicate()->divert_to(outerLoopPredExitVar.output);
1825 exitPredLoopVar.post->divert_to(outerLoopPredExitVar.output);
1826 memLoopVar.post->divert_to(memExitVar.output);
1827 ioLoopVar.post->divert_to(&io2);
1828 opaqueLoopVar.post->divert_to(opaqueLoopVar.pre);
1835 auto & exitGammaNode = *rvsdg::GammaNode::create(exitPredLoopVar.output, 2);
1836 auto pEntryVarExit = exitGammaNode.AddEntryVar(&p);
1837 auto qEntryVarExit = exitGammaNode.AddEntryVar(&q);
1838 auto memEntryVarExit = exitGammaNode.AddEntryVar(memLoopVar.output);
1841 auto & loadP2Node = LoadNonVolatileOperation::CreateNode(
1842 *pEntryVarExit.branchArgument[0],
1843 { memEntryVarExit.branchArgument[0] },
1846 auto & pLoad2 = LoadOperation::LoadedValueOutput(loadP2Node);
1847 auto & mem10 = *LoadOperation::MemoryStateOutputs(loadP2Node).begin();
1850 auto & loadQ2Node = LoadNonVolatileOperation::CreateNode(
1851 *qEntryVarExit.branchArgument[1],
1852 { memEntryVarExit.branchArgument[1] },
1855 auto & qLoad2 = LoadOperation::LoadedValueOutput(loadQ2Node);
1856 auto & mem12 = *LoadOperation::MemoryStateOutputs(loadQ2Node).begin();
1858 auto retExitVar = exitGammaNode.AddExitVar({ &pLoad2, &qLoad2 });
1859 auto memFinalExitVar = exitGammaNode.AddExitVar({ &mem10, &mem12 });
1862 lambdaNode.finalize({ retExitVar.output, ioLoopVar.output, memFinalExitVar.output });
1864 std::cout << rvsdg::view(&graph.GetRootRegion()) << std::endl;
1872 rvsdg::TryGetRegionParentNode<rvsdg::GammaNode>(*retExitVar.branchResult[0]->origin()));
1874 rvsdg::TryGetRegionParentNode<rvsdg::GammaNode>(*retExitVar.branchResult[1]->origin()));
1876 ASSERT_EQ(pLoad.nusers(), 2u);
1877 ASSERT_EQ(qLoad.nusers(), 2u);
1880TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithConstantStruct)
1886 const auto pointerType = PointerType::Create();
1887 const auto bits8Type = BitType::Create(8);
1888 const auto bits32Type = BitType::Create(32);
1889 const auto bits64Type = BitType::Create(64);
1890 const auto structType = StructType::CreateIdentified(
1891 { bits32Type, bits32Type, bits32Type, bits32Type, pointerType },
1893 auto functionType1 = FunctionType::Create({}, {});
1894 const auto functionType2 = FunctionType::Create(
1896 { bits32Type, bits32Type, bits32Type, bits32Type, bits32Type, bits64Type, pointerType });
1899 auto & graph = rvsdgModule.Rvsdg();
1901 auto & i0 = GraphImport::Create(graph, functionType2,
"fct");
1903 auto deltaNode = DeltaNode::Create(
1904 &graph.GetRootRegion(),
1905 DeltaOperation::Create(structType,
true, pointerType));
1907 auto ctxVar = deltaNode->AddContextVar(i0);
1908 auto & zeroNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 0);
1909 auto & oneNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 1);
1910 auto & twoNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 2);
1911 auto & threeNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 3);
1912 auto & fnToPtrNode = FunctionToPointerOperation::createNode(*ctxVar.inner);
1913 auto & constantStructResult = ConstantStructOperation::Create(
1914 *deltaNode->subregion(),
1915 { zeroNode.output(0),
1918 threeNode.output(0),
1919 fnToPtrNode.output(0) },
1921 deltaNode->finalize(&constantStructResult);
1924 auto & lambdaNode = *LambdaNode::Create(
1925 graph.GetRootRegion(),
1926 LlvmLambdaOperation::Create(functionType2,
"func", Linkage::internalLinkage));
1927 auto ctxVar = lambdaNode.AddContextVar(deltaNode->output());
1929 auto zero = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 0).output(0);
1930 auto two = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2).output(0);
1931 auto four = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 4).output(0);
1933 auto & loadNode0 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits32Type, 4);
1935 auto gepOutput1 = GetElementPtrOperation::create(ctxVar.inner, { zero }, bits32Type);
1936 auto & loadNode1 = LoadNonVolatileOperation::CreateNode(*gepOutput1, {}, bits32Type, 4);
1938 auto gepOutput2 = GetElementPtrOperation::create(ctxVar.inner, { zero, zero }, structType);
1939 auto & loadNode2 = LoadNonVolatileOperation::CreateNode(*gepOutput2, {}, bits32Type, 4);
1941 auto gepOutput3 = GetElementPtrOperation::create(ctxVar.inner, { zero, two }, structType);
1942 auto & loadNode3 = LoadNonVolatileOperation::CreateNode(*gepOutput3, {}, bits32Type, 4);
1944 auto gepOutput4 = GetElementPtrOperation::create(ctxVar.inner, { four }, bits8Type);
1945 auto & loadNode4 = LoadNonVolatileOperation::CreateNode(*gepOutput4, {}, bits32Type, 4);
1947 auto & loadNode5 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits64Type, 4);
1949 auto gepOutput6 = GetElementPtrOperation::create(ctxVar.inner, { zero, four }, structType);
1950 auto & loadNode6 = LoadNonVolatileOperation::CreateNode(*gepOutput6, {}, pointerType, 4);
1952 lambdaNode.finalize({ &LoadOperation::LoadedValueOutput(loadNode0),
1953 &LoadOperation::LoadedValueOutput(loadNode1),
1954 &LoadOperation::LoadedValueOutput(loadNode2),
1955 &LoadOperation::LoadedValueOutput(loadNode3),
1956 &LoadOperation::LoadedValueOutput(loadNode4),
1957 &LoadOperation::LoadedValueOutput(loadNode5),
1958 &LoadOperation::LoadedValueOutput(loadNode6) });
1964 auto [intNode0, intOperation0] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1965 *lambdaNode.GetFunctionResults()[0]->origin());
1966 EXPECT_NE(intOperation0,
nullptr);
1967 EXPECT_EQ(intOperation0->Representation().to_uint(), 0u);
1969 auto [intNode1, intOperation1] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1970 *lambdaNode.GetFunctionResults()[1]->origin());
1971 EXPECT_NE(intOperation1,
nullptr);
1972 EXPECT_EQ(intOperation1->Representation().to_uint(), 0u);
1974 auto [intNode2, intOperation2] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1975 *lambdaNode.GetFunctionResults()[2]->origin());
1976 EXPECT_NE(intOperation2,
nullptr);
1977 EXPECT_EQ(intOperation2->Representation().to_uint(), 0u);
1979 auto [intNode3, intOperation3] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1980 *lambdaNode.GetFunctionResults()[3]->origin());
1981 EXPECT_NE(intOperation3,
nullptr);
1982 EXPECT_EQ(intOperation3->Representation().to_uint(), 2u);
1984 auto [intNode4, intOperation4] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1985 *lambdaNode.GetFunctionResults()[4]->origin());
1986 EXPECT_NE(intOperation4,
nullptr);
1987 EXPECT_EQ(intOperation4->Representation().to_uint(), 1u);
1991 auto [loadNode, loadOperation] = TryGetSimpleNodeAndOptionalOp<LoadNonVolatileOperation>(
1992 *lambdaNode.GetFunctionResults()[5]->origin());
1993 EXPECT_NE(loadOperation,
nullptr);
1995 auto [intNode5, intOperation5] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
1996 *lambdaNode.GetFunctionResults()[5]->origin());
1997 EXPECT_NE(intOperation5,
nullptr);
1998 EXPECT_EQ(intOperation5->Representation().to_uint(), 0x0000000100000000u);
2002 auto [fnToPtrNode, fnToPtrOperation] = TryGetSimpleNodeAndOptionalOp<FunctionToPointerOperation>(
2003 *lambdaNode.GetFunctionResults()[6]->origin());
2004 EXPECT_NE(fnToPtrOperation,
nullptr);
2007TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithConstantArray)
2014 auto & graph = rvsdgModule.
Rvsdg();
2015 const auto pointerType = PointerType::Create();
2016 const auto bits8Type = BitType::Create(8);
2017 const auto bits32Type = BitType::Create(32);
2018 const auto bits64Type = BitType::Create(64);
2019 const auto arrayType = ArrayType::Create(bits32Type, 3);
2020 const auto functionType = FunctionType::Create(
2031 auto deltaNode = DeltaNode::Create(
2032 &graph.GetRootRegion(),
2033 DeltaOperation::Create(arrayType,
true, pointerType));
2034 auto & zeroNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 0);
2035 auto & oneNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 1);
2036 auto & twoNode = IntegerConstantOperation::Create(*deltaNode->subregion(), 32, 2);
2037 auto constantDataArrayResult =
2038 ConstantArrayOperation::Create({ zeroNode.output(0), oneNode.output(0), twoNode.output(0) });
2039 auto & deltaOutput = deltaNode->finalize(constantDataArrayResult);
2041 auto & lambdaNode = *LambdaNode::Create(
2042 graph.GetRootRegion(),
2043 LlvmLambdaOperation::Create(functionType,
"func", Linkage::internalLinkage));
2044 auto ctxVar = lambdaNode.AddContextVar(deltaOutput);
2046 auto zero = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 0).output(0);
2047 auto two = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 2).output(0);
2048 auto four = IntegerConstantOperation::Create(*lambdaNode.subregion(), 32, 4).output(0);
2050 auto & loadNode0 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits32Type, 4);
2052 auto gepOutput1 = GetElementPtrOperation::create(ctxVar.inner, { zero }, arrayType);
2053 auto & loadNode1 = LoadNonVolatileOperation::CreateNode(*gepOutput1, {}, bits32Type, 4);
2055 auto gepOutput2 = GetElementPtrOperation::create(ctxVar.inner, { zero, zero }, arrayType);
2056 auto & loadNode2 = LoadNonVolatileOperation::CreateNode(*gepOutput2, {}, bits32Type, 4);
2058 auto gepOutput3 = GetElementPtrOperation::create(ctxVar.inner, { zero, two }, arrayType);
2059 auto & loadNode3 = LoadNonVolatileOperation::CreateNode(*gepOutput3, {}, bits32Type, 4);
2061 auto gepOutput4 = GetElementPtrOperation::create(ctxVar.inner, { four }, bits8Type);
2062 auto & loadNode4 = LoadNonVolatileOperation::CreateNode(*gepOutput4, {}, bits32Type, 4);
2064 auto & loadNode5 = LoadNonVolatileOperation::CreateNode(*ctxVar.inner, {}, bits64Type, 4);
2066 lambdaNode.finalize({
2067 &LoadOperation::LoadedValueOutput(loadNode0),
2068 &LoadOperation::LoadedValueOutput(loadNode1),
2069 &LoadOperation::LoadedValueOutput(loadNode2),
2070 &LoadOperation::LoadedValueOutput(loadNode3),
2071 &LoadOperation::LoadedValueOutput(loadNode4),
2072 &LoadOperation::LoadedValueOutput(loadNode5),
2080 auto [intNode0, intOperation0] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2081 *lambdaNode.GetFunctionResults()[0]->origin());
2082 EXPECT_NE(intOperation0,
nullptr);
2083 EXPECT_EQ(intOperation0->Representation().to_uint(), 0);
2087 auto [intNode1, intOperation1] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2088 *lambdaNode.GetFunctionResults()[1]->origin());
2089 EXPECT_NE(intOperation1,
nullptr);
2090 EXPECT_EQ(intOperation1->Representation().to_uint(), 0);
2094 auto [intNode2, intOperation2] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2095 *lambdaNode.GetFunctionResults()[2]->origin());
2096 EXPECT_NE(intOperation2,
nullptr);
2097 EXPECT_EQ(intOperation2->Representation().to_uint(), 0);
2101 auto [intNode3, intOperation3] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2102 *lambdaNode.GetFunctionResults()[3]->origin());
2103 EXPECT_NE(intOperation3,
nullptr);
2104 EXPECT_EQ(intOperation3->Representation().to_uint(), 2);
2108 auto [intNode4, intOperation4] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2109 *lambdaNode.GetFunctionResults()[4]->origin());
2110 EXPECT_NE(intOperation4,
nullptr);
2111 EXPECT_EQ(intOperation4->Representation().to_uint(), 1);
2116 auto [loadNode, loadOperation] = TryGetSimpleNodeAndOptionalOp<LoadNonVolatileOperation>(
2117 *lambdaNode.GetFunctionResults()[5]->origin());
2118 EXPECT_NE(loadOperation,
nullptr);
2120 auto [intNode5, intOperation5] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2121 *lambdaNode.GetFunctionResults()[5]->origin());
2122 EXPECT_NE(intOperation5,
nullptr);
2123 EXPECT_EQ(intOperation5->Representation().to_uint(), 0x0000000100000000);
2172TEST(StoreValueForwardingTests, LoadForwardingFromDeltaWithConstantGep)
2185 auto & graph = rvsdgModule.
Rvsdg();
2187 const auto pointerType = PointerType::Create();
2188 const auto bits8Type = BitType::Create(8);
2189 const auto bits32Type = BitType::Create(32);
2190 const auto structType =
2191 StructType::CreateIdentified(
"struct.s", { bits32Type, bits32Type },
false);
2194 auto s0 = DeltaNode::Create(
2195 &graph.GetRootRegion(),
2196 DeltaOperation::Create(structType,
true, pointerType));
2197 auto & one = IntegerConstantOperation::Create(*s0->subregion(), 32, 1);
2198 auto & two = IntegerConstantOperation::Create(*s0->subregion(), 32, 2);
2199 auto & s0Value = ConstantStructOperation::Create(
2201 { one.output(0), two.output(0) },
2203 auto & s0Output = s0->finalize(&s0Value);
2206 auto v = DeltaNode::Create(
2207 &graph.GetRootRegion(),
2208 DeltaOperation::Create(pointerType,
true, pointerType));
2209 auto vContext = v->AddContextVar(s0Output);
2210 auto four = IntegerConstantOperation::Create(*v->subregion(), 64, 4).output(0);
2211 auto vValue = GetElementPtrOperation::create(vContext.inner, { four }, bits8Type);
2212 auto & vOutput = v->finalize(vValue);
2214 auto & lambdaNode = *LambdaNode::Create(
2215 graph.GetRootRegion(),
2216 LlvmLambdaOperation::Create(
2217 FunctionType::Create({}, { bits32Type }),
2219 Linkage::internalLinkage));
2220 auto vContextVar = lambdaNode.AddContextVar(vOutput);
2223 auto & pointerLoad = LoadNonVolatileOperation::CreateNode(*vContextVar.inner, {}, pointerType, 8);
2226 LoadNonVolatileOperation::CreateNode(*pointerLoad.output(0), {}, bits32Type, 4);
2227 lambdaNode.finalize({ &LoadOperation::LoadedValueOutput(valueLoad) });
2233 EXPECT_FALSE(Region::containsOperation<LoadNonVolatileOperation>(graph.GetRootRegion(),
true));
2235 auto [intNode, intOperation] = TryGetSimpleNodeAndOptionalOp<IntegerConstantOperation>(
2236 *lambdaNode.GetFunctionResults()[0]->origin());
2237 EXPECT_NE(intNode,
nullptr);
2238 EXPECT_NE(intOperation,
nullptr);
2239 EXPECT_EQ(intOperation->Representation().to_uint(), 2u);