Jlm
Loading...
Searching...
No Matches
MemoryQueueTests.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2024 Magnus Sjalander <work@sjalander.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <gtest/gtest.h>
7
11#include <jlm/hls/ir/hls.hpp>
17#include <jlm/rvsdg/lambda.hpp>
18#include <jlm/rvsdg/theta.hpp>
20#include <jlm/rvsdg/view.hpp>
22
23TEST(MemoryQueueTests, TestSingleLoad)
24{
25 using namespace jlm::llvm;
26 using namespace jlm::hls;
27
28 auto rvsdgModule = LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
29
30 // Setup the function
31 std::cout << "Function Setup" << std::endl;
32 auto functionType = jlm::rvsdg::FunctionType::Create(
33 { jlm::llvm::PointerType::Create(), MemoryStateType::Create() },
34 { jlm::llvm::PointerType::Create(), MemoryStateType::Create() });
35
37 rvsdgModule->Rvsdg().GetRootRegion(),
38 LlvmLambdaOperation::Create(functionType, "test", Linkage::externalLinkage));
39
40 // Theta
41 auto theta = jlm::rvsdg::ThetaNode::create(lambda->subregion());
42 auto constant = &jlm::rvsdg::BitConstantOperation::create(*theta->subregion(), { 1, 1 });
43 auto & matchNode = jlm::rvsdg::MatchOperation::CreateNode(*constant, { { 1, 1 } }, 0, 2);
44 theta->set_predicate(matchNode.output(0));
45
46 // Load node
47 auto functionArguments = lambda->GetFunctionArguments();
48 auto loadAddress = theta->AddLoopVar(functionArguments[0]);
49 auto memoryStateArgument = theta->AddLoopVar(functionArguments[1]);
50 auto loadOutput = LoadNonVolatileOperation::Create(
51 loadAddress.pre,
52 { memoryStateArgument.pre },
53 PointerType::Create(),
54 32);
55 loadAddress.post->divert_to(loadOutput[0]);
56 memoryStateArgument.post->divert_to(loadOutput[1]);
57
58 auto lambdaOutput = lambda->finalize({ theta->output(0), theta->output(1) });
59 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "f");
60
61 auto lambdaRegion = lambda->subregion();
62 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
63
64 // Act
66 MemoryStateSeparation::CreateAndRun(*rvsdgModule, statisticsCollector);
67
68 // Assert
69 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
70 auto & entryMemoryStateSplitInput = lambdaRegion->argument(1)->SingleUser();
71 auto * entryMemoryStateSplitNode =
73 jlm::util::assertedCast<const LambdaEntryMemoryStateSplitOperation>(
74 &entryMemoryStateSplitNode->GetOperation());
75 auto exitMemoryStateMergeNode =
76 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*lambdaRegion->result(1)->origin());
77 jlm::util::assertedCast<const LambdaExitMemoryStateMergeOperation>(
78 &exitMemoryStateMergeNode->GetOperation());
79
80 // Act
81 ThetaNodeConversion::CreateAndRun(*rvsdgModule, statisticsCollector);
82 // Simple assert as ConvertThetaNodes() is tested in separate unit tests
83 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
84 EXPECT_TRUE(jlm::rvsdg::Region::containsNodeType<LoopNode>(*lambdaRegion, true));
85
86 // Act
87 AddressQueueInsertion::CreateAndRun(*rvsdgModule, statisticsCollector);
88
89 // Assert
90 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
91 EXPECT_TRUE(jlm::rvsdg::Region::containsOperation<StateGateOperation>(*lambdaRegion, true));
92 EXPECT_FALSE(jlm::rvsdg::Region::containsOperation<AddressQueueOperation>(*lambdaRegion, true));
93}
94
95TEST(MemoryQueueTests, TestLoadStore)
96{
97 using namespace jlm::llvm;
98 using namespace jlm::hls;
99
100 auto rvsdgModule = LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
101
102 // Setup the function
103 std::cout << "Function Setup" << std::endl;
104 auto functionType = jlm::rvsdg::FunctionType::Create(
107 MemoryStateType::Create() },
108 { jlm::llvm::PointerType::Create(), MemoryStateType::Create() });
109
110 auto lambda = jlm::rvsdg::LambdaNode::Create(
111 rvsdgModule->Rvsdg().GetRootRegion(),
112 LlvmLambdaOperation::Create(functionType, "test", Linkage::externalLinkage));
113
114 // Theta
115 auto theta = jlm::rvsdg::ThetaNode::create(lambda->subregion());
116 auto constant = &jlm::rvsdg::BitConstantOperation::create(*theta->subregion(), { 1, 1 });
117 auto & matchNode = jlm::rvsdg::MatchOperation::CreateNode(*constant, { { 1, 1 } }, 0, 2);
118 theta->set_predicate(matchNode.output(0));
119
120 // Load node
121 auto functionArguments = lambda->GetFunctionArguments();
122 auto loadAddress = theta->AddLoopVar(functionArguments[0]);
123 auto storeAddress = theta->AddLoopVar(functionArguments[1]);
124 auto memoryStateArgument = theta->AddLoopVar(functionArguments[2]);
125 auto loadOutput = LoadNonVolatileOperation::Create(
126 loadAddress.pre,
127 { memoryStateArgument.pre },
128 PointerType::Create(),
129 32);
130 auto storeOutput = StoreNonVolatileOperation::Create(
131 storeAddress.pre,
132 &jlm::rvsdg::BitConstantOperation::create(*theta->subregion(), { 32, 1 }),
133 { loadOutput[1] },
134 32);
135
136 loadAddress.post->divert_to(loadOutput[0]);
137 memoryStateArgument.post->divert_to(storeOutput[0]);
138
139 auto lambdaOutput = lambda->finalize({ theta->output(0), theta->output(2) });
140 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "f");
141
142 auto lambdaRegion = lambda->subregion();
143 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
144
145 // Act
147 MemoryStateSeparation::CreateAndRun(*rvsdgModule, statisticsCollector);
148
149 // Assert
150 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
151 auto & entryMemoryStateSplitInput = lambdaRegion->argument(2)->SingleUser();
152 auto * entryMemoryStateSplitNode =
153 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(entryMemoryStateSplitInput);
154 jlm::util::assertedCast<const LambdaEntryMemoryStateSplitOperation>(
155 &entryMemoryStateSplitNode->GetOperation());
156 auto exitMemoryStateMergeNode =
157 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*lambdaRegion->result(1)->origin());
158 jlm::util::assertedCast<const LambdaExitMemoryStateMergeOperation>(
159 &exitMemoryStateMergeNode->GetOperation());
160
161 // Act
162 ThetaNodeConversion::CreateAndRun(*rvsdgModule, statisticsCollector);
163 // Simple assert as ConvertThetaNodes() is tested in separate unit tests
164 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
165 EXPECT_TRUE(jlm::rvsdg::Region::containsNodeType<LoopNode>(*lambdaRegion, true));
166
167 // Act
168 AddressQueueInsertion::CreateAndRun(*rvsdgModule, statisticsCollector);
169
170 // Assert
171 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
172 EXPECT_TRUE(jlm::rvsdg::Region::containsOperation<StateGateOperation>(*lambdaRegion, true));
173 EXPECT_FALSE(jlm::rvsdg::Region::containsOperation<AddressQueueOperation>(*lambdaRegion, true));
174}
175
176TEST(MemoryQueueTests, TestAddrQueue)
177{
178 using namespace jlm::llvm;
179 using namespace jlm::hls;
180
181 auto rvsdgModule = LlvmRvsdgModule::Create(jlm::util::FilePath(""), "", "");
182
183 // Setup the function
184 std::cout << "Function Setup" << std::endl;
185 auto functionType = jlm::rvsdg::FunctionType::Create(
186 { jlm::llvm::PointerType::Create(), MemoryStateType::Create() },
187 { jlm::llvm::PointerType::Create(), MemoryStateType::Create() });
188
189 auto lambda = jlm::rvsdg::LambdaNode::Create(
190 rvsdgModule->Rvsdg().GetRootRegion(),
191 LlvmLambdaOperation::Create(functionType, "test", Linkage::externalLinkage));
192
193 // Theta
194 auto theta = jlm::rvsdg::ThetaNode::create(lambda->subregion());
195 auto constant = &jlm::rvsdg::BitConstantOperation::create(*theta->subregion(), { 1, 1 });
196 auto & matchNode = jlm::rvsdg::MatchOperation::CreateNode(*constant, { { 1, 1 } }, 0, 2);
197 theta->set_predicate(matchNode.output(0));
198
199 // Load node
200 auto functionArguments = lambda->GetFunctionArguments();
201 auto address = theta->AddLoopVar(functionArguments[0]);
202 auto memoryStateArgument = theta->AddLoopVar(functionArguments[1]);
203 auto loadOutput = LoadNonVolatileOperation::Create(
204 address.pre,
205 { memoryStateArgument.pre },
206 PointerType::Create(),
207 32);
208 auto storeOutput =
209 StoreNonVolatileOperation::Create(address.pre, loadOutput[0], { loadOutput[1] }, 32);
210
211 address.post->divert_to(loadOutput[0]);
212 memoryStateArgument.post->divert_to(storeOutput[0]);
213
214 auto lambdaOutput = lambda->finalize({ theta->output(0), theta->output(1) });
215 jlm::rvsdg::GraphExport::Create(*lambdaOutput, "f");
216
217 auto lambdaRegion = lambda->subregion();
218 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
219
220 // Act
222 MemoryStateSeparation::CreateAndRun(*rvsdgModule, statisticsCollector);
223
224 // Assert
225 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
226 auto & entryMemoryStateSplitInput = lambdaRegion->argument(1)->SingleUser();
227 auto * entryMemoryStateSplitNode =
228 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(entryMemoryStateSplitInput);
229 jlm::util::assertedCast<const LambdaEntryMemoryStateSplitOperation>(
230 &entryMemoryStateSplitNode->GetOperation());
231 auto exitMemoryStateMergeNode =
232 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*lambdaRegion->result(1)->origin());
233 jlm::util::assertedCast<const LambdaExitMemoryStateMergeOperation>(
234 &exitMemoryStateMergeNode->GetOperation());
235
236 // Act
237 ThetaNodeConversion::CreateAndRun(*rvsdgModule, statisticsCollector);
238 // Simple assert as ConvertThetaNodes() is tested in separate unit tests
239 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
240 EXPECT_TRUE(jlm::rvsdg::Region::containsNodeType<LoopNode>(*lambdaRegion, true));
241
242 // Act
243 AddressQueueInsertion::CreateAndRun(*rvsdgModule, statisticsCollector);
244
245 // Assert
246 jlm::rvsdg::view(rvsdgModule->Rvsdg(), stdout);
247 EXPECT_TRUE(jlm::rvsdg::Region::containsOperation<StateGateOperation>(*lambdaRegion, true));
248 EXPECT_TRUE(jlm::rvsdg::Region::containsOperation<AddressQueueOperation>(*lambdaRegion, true));
249
250 for (auto & node : jlm::rvsdg::TopDownTraverser(lambdaRegion))
251 {
252 if (auto loopNode = dynamic_cast<jlm::hls::LoopNode *>(node))
253 {
254 for (auto & node : jlm::rvsdg::TopDownTraverser(loopNode->subregion()))
255 {
256 if (is<StoreNonVolatileOperation>(node))
257 {
258 auto loadNode =
260 jlm::util::assertedCast<const jlm::llvm::LoadOperation>(&loadNode->GetOperation());
261 auto stateGate =
262 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*loadNode->input(0)->origin());
263 jlm::util::assertedCast<const StateGateOperation>(&stateGate->GetOperation());
264 auto addrQueue =
265 jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*stateGate->input(0)->origin());
266 jlm::util::assertedCast<const AddressQueueOperation>(&addrQueue->GetOperation());
267 }
268 }
269 }
270 }
271}
static jlm::util::StatisticsCollector statisticsCollector
TEST(MemoryQueueTests, TestSingleLoad)
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
static Output & create(Region &region, BitValueRepresentation value)
Definition constant.hpp:44
static std::shared_ptr< const FunctionType > Create(std::vector< std::shared_ptr< const jlm::rvsdg::Type > > argumentTypes, std::vector< std::shared_ptr< const jlm::rvsdg::Type > > resultTypes)
static GraphExport & Create(Output &origin, std::string name)
Definition graph.cpp:62
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
Definition lambda.cpp:141
static Node & CreateNode(Output &predicate, const std::unordered_map< uint64_t, uint64_t > &mapping, const uint64_t defaultAlternative, const size_t numAlternatives)
Definition control.hpp:220
static ThetaNode * create(rvsdg::Region *parent)
Definition theta.hpp:73
Global memory state passed between functions.
std::string view(const rvsdg::Region *region)
Definition view.cpp:142
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
detail::TopDownTraverserGeneric< false > TopDownTraverser
Traverser for visiting every node in a region in a top down order.