6 #include <gtest/gtest.h>
20 TEST(LoadOperationTests, OperationEquality)
37 EXPECT_EQ(operation1, operation1);
38 EXPECT_NE(operation1, operation2);
39 EXPECT_NE(operation1, operation3);
40 EXPECT_NE(operation1, operation4);
41 EXPECT_NE(operation1, operation5);
44 TEST(LoadOperationTests, TestCopy)
63 auto node = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*loadResults[0]);
64 EXPECT_TRUE(is<LoadNonVolatileOperation>(node));
65 auto copiedNode = node->copy(&graph.
GetRootRegion(), { address2, memoryState2 });
70 jlm::util::assertedCast<jlm::rvsdg::SimpleNode>(copiedNode)->GetOperation());
73 TEST(LoadOperationTests, TestLoadAllocaReduction)
95 jlm::rvsdg::ReduceNode<LoadNonVolatileOperation>(
103 auto node = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*ex.origin());
104 EXPECT_TRUE(is<LoadNonVolatileOperation>(node));
105 EXPECT_EQ(node->ninputs(), 3u);
106 EXPECT_EQ(node->input(1)->origin(), alloca1[1]);
107 EXPECT_EQ(node->input(2)->origin(), mux);
110 TEST(LoadOperationTests, TestDuplicateStateReduction)
137 const auto success = jlm::rvsdg::ReduceNode<LoadNonVolatileOperation>(
144 EXPECT_TRUE(success);
145 const auto node = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*exA.origin());
146 EXPECT_TRUE(is<LoadNonVolatileOperation>(node));
147 EXPECT_EQ(node->ninputs(), 4u);
148 EXPECT_EQ(node->noutputs(), 4u);
150 EXPECT_EQ(exA.origin(), node->output(0));
151 EXPECT_EQ(exS1.origin(), node->output(1));
152 EXPECT_EQ(exS2.origin(), node->output(2));
153 EXPECT_EQ(exS3.origin(), node->output(1));
154 EXPECT_EQ(exS4.origin(), node->output(2));
155 EXPECT_EQ(exS5.origin(), node->output(3));
158 TEST(LoadOperationTests, TestLoadStoreStateReduction)
183 const auto success1 = jlm::rvsdg::ReduceNode<LoadNonVolatileOperation>(
186 const auto success2 = jlm::rvsdg::ReduceNode<LoadNonVolatileOperation>(
194 EXPECT_TRUE(success1);
195 auto node = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*ex1.origin());
196 EXPECT_TRUE(is<LoadNonVolatileOperation>(node));
197 EXPECT_EQ(node->ninputs(), 2u);
199 EXPECT_FALSE(success2);
200 node = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*ex2.origin());
201 EXPECT_TRUE(is<LoadNonVolatileOperation>(node));
202 EXPECT_EQ(node->ninputs(), 2u);
205 TEST(LoadOperationTests, TestLoadStoreReduction_Success)
228 const auto success = jlm::rvsdg::ReduceNode<LoadNonVolatileOperation>(
235 EXPECT_TRUE(success);
237 EXPECT_EQ(x1.origin(), v);
238 EXPECT_EQ(x2.origin(), s1);
245 TEST(LoadOperationTests, LoadStoreReduction_DifferentValueOperandType)
271 const auto success = jlm::rvsdg::ReduceNode<LoadNonVolatileOperation>(
279 EXPECT_FALSE(success);
281 const auto expectedLoadNode =
282 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*exportedValue.origin());
283 EXPECT_EQ(expectedLoadNode, &loadNode);
284 EXPECT_EQ(expectedLoadNode->ninputs(), 2u);
286 const auto expectedStoreNode =
287 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*expectedLoadNode->input(1)->origin());
288 EXPECT_EQ(expectedStoreNode, &storeNode);
291 TEST(LoadOperationTests, IOBarrierAllocaAddressNormalization)
309 auto & ioBarrierNode = jlm::rvsdg::CreateOpNode<IOBarrierOperation>(
310 { allocaResults[0], ioStateImport },
314 *ioBarrierNode.output(0),
315 { allocaResults[1] },
328 const auto successLoadNode1 = jlm::rvsdg::ReduceNode<LoadNonVolatileOperation>(
332 const auto successLoadNode2 = jlm::rvsdg::ReduceNode<LoadNonVolatileOperation>(
340 EXPECT_TRUE(successLoadNode1);
342 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*ex1.origin())->input(0)->origin(),
347 EXPECT_FALSE(successLoadNode2);
349 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*ex2.origin())->input(0)->origin(),
353 TEST(LoadOperationTests, IOBarrierAllocaAddressNormalization_Gamma)
359 const auto valueType = TestType::createValueType();
364 const auto controlType = ControlType::Create(2);
374 auto gammaNode = GammaNode::create(controlImport, 2);
375 auto addressEntryVar = gammaNode->AddEntryVar(allocaResults[0]);
376 auto memoryStateEntryVar = gammaNode->AddEntryVar(allocaResults[1]);
377 auto ioStateEntryVar = gammaNode->AddEntryVar(ioStateImport);
378 auto valueEntryVar = gammaNode->AddEntryVar(valueImport);
380 auto & ioBarrierNode = jlm::rvsdg::CreateOpNode<IOBarrierOperation>(
381 { addressEntryVar.branchArgument[0], ioStateEntryVar.branchArgument[0] },
385 *ioBarrierNode.output(0),
386 { memoryStateEntryVar.branchArgument[0] },
390 auto exitVar = gammaNode->AddExitVar({ loadNode.output(0), valueEntryVar.branchArgument[1] });
392 GraphExport::Create(*exitVar.output,
"load1");
397 const auto successLoadNode = jlm::rvsdg::ReduceNode<LoadNonVolatileOperation>(
406 EXPECT_TRUE(successLoadNode);
409 EXPECT_EQ(gammaNode->subregion(0)->numNodes(), 1u);
411 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::Node>(*exitVar.branchResult[0]->origin())
414 addressEntryVar.branchArgument[0]);
417 TEST(LoadOperationTests, LoadVolatileOperationEquality)
434 EXPECT_EQ(operation1, operation1);
435 EXPECT_NE(operation1, operation2);
436 EXPECT_NE(operation1, operation3);
437 EXPECT_NE(operation1, operation4);
438 EXPECT_NE(operation1, operation5);
441 TEST(LoadOperationTests, OperationCopy)
453 auto copiedOperation = operation.
copy();
456 EXPECT_EQ(*copiedOperation, operation);
459 TEST(LoadOperationTests, OperationAccessors)
468 size_t alignment = 4;
469 size_t numMemoryStates = 2;
476 EXPECT_EQ(operation.
narguments(), numMemoryStates + 2);
477 EXPECT_EQ(operation.
nresults(), numMemoryStates + 2);
480 TEST(LoadOperationTests, NodeCopy)
490 auto valueType = TestType::createValueType();
501 auto & loadNode = jlm::rvsdg::CreateOpNode<LoadVolatileOperation>(
502 { &address1, &iOState1, &memoryState1 },
508 auto copiedNode = loadNode.copy(&graph.
GetRootRegion(), { &address2, &iOState2, &memoryState2 });
512 &jlm::util::assertedCast<SimpleNode>(copiedNode)->GetOperation());
513 EXPECT_NE(copiedOperation,
nullptr);
516 EXPECT_EQ(*copiedOperation->GetLoadedType(), *valueType);
static std::vector< rvsdg::Output * > create(std::shared_ptr< const rvsdg::Type > allocatedType, rvsdg::Output *count, const size_t alignment)
static std::shared_ptr< const IOStateType > Create()
static rvsdg::SimpleNode & CreateNode(rvsdg::Region ®ion, std::unique_ptr< LoadNonVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
static std::optional< std::vector< rvsdg::Output * > > NormalizeIOBarrierAllocaAddress(const LoadNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Redirect the address operand of the LoadNonVolatileOperation from an IOBarrierOperation when it can b...
static std::optional< std::vector< rvsdg::Output * > > NormalizeLoadStoreState(const LoadNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
If the producer of a load's address is an alloca operation, then we can remove all state edges origin...
static std::optional< std::vector< rvsdg::Output * > > NormalizeDuplicateStates(const LoadNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Remove duplicated state operands.
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *state, std::shared_ptr< const rvsdg::Type > loadedType, size_t alignment)
static std::optional< std::vector< rvsdg::Output * > > NormalizeLoadAlloca(const LoadNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
If the producer of a load's address is an alloca operation, then we can remove all state edges origin...
static std::optional< std::vector< rvsdg::Output * > > NormalizeLoadStore(const LoadNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Forwards the value from a store operation.
size_t NumMemoryStates() const noexcept
std::shared_ptr< const rvsdg::Type > GetLoadedType() const noexcept
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
size_t GetAlignment() const noexcept
static rvsdg::Input & IOStateInput(const rvsdg::Node &node) noexcept
std::unique_ptr< Operation > copy() const override
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &operands)
static std::shared_ptr< const MemoryStateType > Create()
static std::shared_ptr< const PointerType > Create()
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *state, size_t alignment)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
static GraphExport & Create(Output &origin, std::string name)
static GraphImport & Create(Graph &graph, std::shared_ptr< const rvsdg::Type > type, std::string name)
Region & GetRootRegion() const noexcept
size_t numNodes() const noexcept
size_t nresults() const noexcept
size_t narguments() const noexcept
static std::shared_ptr< const TestType > createValueType()
TEST(LoadTests, LoadConversion)
Global memory state passed between functions.
std::string view(const rvsdg::Region *region)
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)