Jlm
Loading...
Searching...
No Matches
hls.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 David Metz <david.c.metz@ntnu.no>
3 * See COPYING for terms of redistribution.
4 */
5
6#include <cmath>
7#include <jlm/hls/ir/hls.hpp>
8#include <jlm/util/Hash.hpp>
9
10namespace jlm::hls
11{
12
14
15ForkOperation::~ForkOperation() noexcept = default;
16
17MuxOperation::~MuxOperation() noexcept = default;
18
19SinkOperation::~SinkOperation() noexcept = default;
20
21PredicateBufferOperation::~PredicateBufferOperation() noexcept = default;
22
23LoopConstantBufferOperation::~LoopConstantBufferOperation() noexcept = default;
24
25BundleType::~BundleType() noexcept = default;
26
27LoopOperation::~LoopOperation() noexcept = default;
28
29PrintOperation::~PrintOperation() noexcept = default;
30
31BufferOperation::~BufferOperation() noexcept = default;
32
33TriggerOperation::~TriggerOperation() noexcept = default;
34
35TriggerType::~TriggerType() noexcept = default;
36
37StateGateOperation::~StateGateOperation() noexcept = default;
38
39LoadOperation::~LoadOperation() noexcept = default;
40
41DecoupledLoadOperation::~DecoupledLoadOperation() noexcept = default;
42
43AddressQueueOperation::~AddressQueueOperation() noexcept = default;
44
45MemoryResponseOperation::~MemoryResponseOperation() noexcept = default;
46
47LocalLoadOperation::~LocalLoadOperation() noexcept = default;
48
49LocalMemoryOperation::~LocalMemoryOperation() noexcept = default;
50
51LocalMemoryRequestOperation::~LocalMemoryRequestOperation() noexcept = default;
52
53LocalMemoryResponseOperation::~LocalMemoryResponseOperation() noexcept = default;
54
55LocalStoreOperation::~LocalStoreOperation() noexcept = default;
56
57StoreOperation::~StoreOperation() noexcept = default;
58
59std::size_t
61{
62 return typeid(TriggerType).hash_code();
63}
64
70
71std::shared_ptr<const TriggerType>
73{
74 static const TriggerType instance;
75 return std::shared_ptr<const TriggerType>(std::shared_ptr<void>(), &instance);
76}
77
78std::size_t
80{
81 std::size_t seed = typeid(BundleType).hash_code();
82 for (auto & element : elements_)
83 {
84 auto firstHash = std::hash<std::string>()(element.first);
85 util::combineHashesWithSeed(seed, firstHash, element.second->ComputeHash());
86 }
87
88 return seed;
89}
90
96
98
100EntryArgument::Copy(rvsdg::Region & region, rvsdg::StructuralInput * input) const
101{
102 return Create(region, *input, Type());
103}
104
107{
108 JLM_ASSERT(input == nullptr);
109 return create(&region, Type());
110}
111
114{
115 JLM_ASSERT(output == nullptr);
116 return create(&origin);
117}
118
120
121ExitResult::ExitResult(rvsdg::Output & origin, rvsdg::StructuralOutput & output)
122 : rvsdg::RegionResult(origin.region(), &origin, &output, origin.Type())
123{
124 JLM_ASSERT(dynamic_cast<const LoopNode *>(origin.region()->node()));
125}
126
129{
130 return Create(origin, *output);
131}
132
135{
136 // Create StructuralInput and EntryArgument
137 const auto input =
138 addInput(std::make_unique<rvsdg::StructuralInput>(this, origin, origin->Type()), true);
139 auto & argument_in = EntryArgument::Create(*subregion(), *input, origin->Type());
140
141 // Create back-edge
142 auto backedge_argument = add_backedge(origin->Type());
143 auto backedge_result = backedge_argument->result();
144
145 // Create Mux to pick between EntryArgument and BackEdgeArgument
149 false,
150 true)[0];
151 // Give the caller a
152 if (buffer != nullptr)
153 *buffer = mux;
154
155 // Create Branch to send the result to either an ExitResult or a BackEdgeResult
156 // We need to give it a value, so use the output of the mux as the result for now
157 auto branch = BranchOperation::create(*predicate()->origin(), *mux, true);
158
159 // Create an ExitResult + StructuralOutput for when the loop is finished
160 const auto output = addOutput(std::make_unique<rvsdg::StructuralOutput>(this, origin->Type()));
162
163 // If the loop is not done, send the value to the BackEdgeResult, with a small buffer in between.
164 auto buf = BufferOperation::create(*branch[1], 2)[0];
165 backedge_result->divert_to(buf);
166 return output;
167}
168
171{
172 auto input =
173 addInput(std::make_unique<rvsdg::StructuralInput>(this, origin, origin->Type()), true);
174
175 auto & argument_in = EntryArgument::Create(*subregion(), *input, origin->Type());
177 return buffer;
178}
179
182{
183 const auto input =
184 addInput(std::make_unique<rvsdg::StructuralInput>(this, origin, origin->Type()), true);
185 return &EntryArgument::Create(*subregion(), *input, origin->Type());
186}
187
190{
191 const auto output = addOutput(std::make_unique<rvsdg::StructuralOutput>(this, origin->Type()));
192 ExitResult::Create(*origin, *output);
193 return output;
194}
195
196void
198{
199 JLM_ASSERT(output->node() == this);
201 JLM_ASSERT(output->results.size() == 1);
202 auto result = output->results.begin();
203
204 subregion()->RemoveResults({ result->index() });
205 RemoveOutputs({ output->index() });
206}
207
208void
210{
211 JLM_ASSERT(input->node() == this);
213 auto argument = input->arguments.begin();
214 JLM_ASSERT(argument->IsDead());
215
216 subregion()->RemoveArguments({ argument->index() });
217 RemoveInputs({ input->index() });
218}
219
220[[nodiscard]] const rvsdg::Operation &
222{
223 static const LoopOperation singleton;
224 return singleton;
225}
226
227LoopNode *
229{
230 auto loop = create(region, false);
231
232 for (size_t i = 0; i < ninputs(); ++i)
233 {
234 auto in_origin = &smap.lookup(*input(i)->origin());
235 auto inp = loop->addInput(
236 std::make_unique<rvsdg::StructuralInput>(loop, in_origin, in_origin->Type()),
237 true);
238
239 auto oarg = input(i)->arguments.begin().ptr();
240 auto & narg = EntryArgument::Create(*loop->subregion(), *inp, oarg->Type());
241 smap.insert(oarg, &narg);
242 }
243 for (size_t i = 0; i < noutputs(); ++i)
244 {
245 auto out = loop->addOutput(std::make_unique<rvsdg::StructuralOutput>(loop, output(i)->Type()));
246
247 smap.insert(output(i), out);
248 smap.insert(output(i), out);
249 }
250 for (size_t i = 0; i < subregion()->narguments(); ++i)
251 {
252 auto arg = subregion()->argument(i);
253 if (auto ba = dynamic_cast<BackEdgeArgument *>(arg))
254 {
255 auto na = loop->add_backedge(arg->Type());
256 smap.insert(ba, na);
257 }
258 }
259
260 subregion()->copy(loop->subregion(), smap);
261 loop->PredicateBuffer_ = &smap.lookup(*PredicateBuffer_);
262 // redirect backedges
263 for (size_t i = 0; i < subregion()->narguments(); ++i)
264 {
265 auto arg = subregion()->argument(i);
266 if (auto ba = dynamic_cast<BackEdgeArgument *>(arg))
267 {
268 auto na = dynamic_cast<BackEdgeArgument *>(&smap.lookup(*ba));
269 na->result()->divert_to(&smap.lookup(*ba->result()->origin()));
270 }
271 }
272 for (size_t i = 0; i < noutputs(); ++i)
273 {
274 auto outp = output(i);
275 auto res = outp->results.begin().ptr();
276 auto origin = &smap.lookup(*res->origin());
277 ExitResult::Create(*origin, *loop->output(i));
278 }
279
280 return loop;
281}
282
284LoopNode::add_backedge(std::shared_ptr<const jlm::rvsdg::Type> type)
285{
286 auto & argument_loop = BackEdgeArgument::create(subregion(), std::move(type));
288 argument_loop.result_ = &result_loop;
289 result_loop.argument_ = &argument_loop;
290 return &argument_loop;
291}
292
293LoopNode *
294LoopNode::create(rvsdg::Region * parent, bool init)
295{
296 auto ln = new LoopNode(parent);
297 if (init)
298 {
300 auto pred_arg = ln->add_backedge(rvsdg::ControlType::Create(2));
301 pred_arg->result()->divert_to(predicate);
302 // we need a buffer without pass-through behavior to avoid a combinatorial cycle of ready
303 // signals
305 ln->PredicateBuffer_ = PredicateBufferOperation::create(*pre_buffer)[0];
306 }
307 return ln;
308}
309
310void
312{
313 auto node = rvsdg::TryGetOwnerNode<Node>(*predicate()->origin());
315 if (node && node->IsDead())
316 remove(node);
317}
318
319std::shared_ptr<const BundleType>
320get_mem_req_type(std::shared_ptr<const rvsdg::Type> elementType, bool write)
321{
322 std::vector<std::pair<std::string, std::shared_ptr<const jlm::rvsdg::Type>>> elements;
323 elements.emplace_back("addr", llvm::PointerType::Create());
324 elements.emplace_back("size", jlm::rvsdg::BitType::Create(4));
325 elements.emplace_back("id", jlm::rvsdg::BitType::Create(8));
326 if (write)
327 {
328 elements.emplace_back("data", std::move(elementType));
329 elements.emplace_back("write", jlm::rvsdg::BitType::Create(1));
330 }
331 return std::make_shared<BundleType>(std::move(elements));
332}
333
334std::shared_ptr<const BundleType>
335get_mem_res_type(std::shared_ptr<const jlm::rvsdg::Type> dataType)
336{
337 std::vector<std::pair<std::string, std::shared_ptr<const jlm::rvsdg::Type>>> elements;
338 elements.emplace_back("data", std::move(dataType));
339 elements.emplace_back("id", jlm::rvsdg::BitType::Create(8));
340 return std::make_shared<BundleType>(std::move(elements));
341}
342
343int
345{
346 if (auto bt = dynamic_cast<const jlm::rvsdg::BitType *>(type))
347 {
348 return bt->nbits();
349 }
350 else if (auto at = dynamic_cast<const llvm::ArrayType *>(type))
351 {
352 return JlmSize(&at->element_type()) * at->nelements();
353 }
354 else if (auto vt = dynamic_cast<const llvm::VectorType *>(type))
355 {
356 return JlmSize(&vt->type()) * vt->size();
357 }
358 else if (dynamic_cast<const llvm::PointerType *>(type))
359 {
360 return GetPointerSizeInBits();
361 }
362 else if (auto ct = dynamic_cast<const rvsdg::ControlType *>(type))
363 {
364 return ceil(log2(ct->nalternatives()));
365 }
366 else if (type->Kind() == rvsdg::TypeKind::State)
367 {
368 return 1;
369 }
370 else if (rvsdg::is<BundleType>(*type))
371 {
372 // TODO: fix this ugly hack needed for get_node_name
373 return 0;
374 }
375 else if (auto ft = dynamic_cast<const llvm::FloatingPointType *>(type))
376 {
377 switch (ft->size())
378 {
380 return 16;
382 return 32;
384 return 64;
385 default:
386 throw std::logic_error("Size of '" + type->debug_string() + "' is not implemented!");
387 }
388 }
389 else
390 {
391 throw std::logic_error("Size of '" + type->debug_string() + "' is not implemented!");
392 }
393}
394
395size_t
397{
398 return 64;
399}
400}
static const auto vt
Definition PullTests.cpp:16
BackEdgeResult * result()
Definition hls.hpp:632
static BackEdgeArgument & create(rvsdg::Region *region, std::shared_ptr< const jlm::rvsdg::Type > type)
Definition hls.hpp:641
BackEdgeArgument & Copy(rvsdg::Region &region, rvsdg::StructuralInput *input) const override
Definition hls.cpp:106
BackEdgeResult & Copy(rvsdg::Output &origin, rvsdg::StructuralOutput *output) const override
Definition hls.cpp:113
static BackEdgeResult & create(jlm::rvsdg::Output *origin)
Definition hls.hpp:673
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &predicate, jlm::rvsdg::Output &value, bool loop=false)
Definition hls.hpp:68
~BranchOperation() noexcept override
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &value, size_t capacity, bool pass_through=false)
Definition hls.hpp:438
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition hls.cpp:92
const std::vector< std::pair< std::string, std::shared_ptr< const jlm::rvsdg::Type > > > elements_
Definition hls.hpp:890
std::size_t ComputeHash() const noexcept override
Definition hls.cpp:79
~EntryArgument() noexcept override
static EntryArgument & Create(rvsdg::Region &region, rvsdg::StructuralInput &input, const std::shared_ptr< const rvsdg::Type > type)
Definition hls.hpp:608
ExitResult & Copy(rvsdg::Output &origin, rvsdg::StructuralOutput *output) const override
Definition hls.cpp:128
static ExitResult & Create(rvsdg::Output &origin, rvsdg::StructuralOutput &output)
Definition hls.hpp:700
~ExitResult() noexcept override
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &predicate, jlm::rvsdg::Output &value)
Definition hls.hpp:378
LoopNode * copy(rvsdg::Region *region, rvsdg::SubstitutionMap &smap) const override
Copy a node with substitutions.
Definition hls.cpp:228
rvsdg::Output * addRequestOutput(rvsdg::Output *origin)
Definition hls.cpp:189
rvsdg::RegionResult * predicate() const noexcept
Definition hls.hpp:731
void removeLoopOutput(rvsdg::StructuralOutput *output)
Definition hls.cpp:197
static LoopNode * create(rvsdg::Region *parent, bool init=true)
Definition hls.cpp:294
rvsdg::Output * PredicateBuffer_
Definition hls.hpp:819
rvsdg::Output & GetPredicateBuffer() const noexcept
Definition hls.hpp:739
rvsdg::StructuralOutput * AddLoopVar(rvsdg::Output *origin, rvsdg::Output **buffer=nullptr)
Definition hls.cpp:134
const rvsdg::Operation & GetOperation() const noexcept override
Definition hls.cpp:221
void set_predicate(jlm::rvsdg::Output *p)
Definition hls.cpp:311
rvsdg::Region * subregion() const noexcept
Definition hls.hpp:725
rvsdg::Output * addLoopConstant(rvsdg::Output *origin)
Definition hls.cpp:170
rvsdg::Output * addResponseInput(rvsdg::Output *origin)
Definition hls.cpp:181
BackEdgeArgument * add_backedge(std::shared_ptr< const jlm::rvsdg::Type > type)
Definition hls.cpp:284
void removeLoopInput(rvsdg::StructuralInput *input)
Definition hls.cpp:209
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &predicate, const std::vector< jlm::rvsdg::Output * > &alternatives, bool discarding, bool loop=false)
Definition hls.hpp:235
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &predicate)
Definition hls.hpp:337
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition hls.cpp:66
static std::shared_ptr< const TriggerType > Create()
Definition hls.cpp:72
PointerType class.
Definition types.hpp:25
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
Definition type.cpp:45
static Output & createFalse(Region &region)
Definition control.hpp:134
static std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
Definition control.cpp:50
void divert_to(Output *new_origin)
Definition node.cpp:64
size_t index() const noexcept
Definition node.hpp:52
Output * origin() const noexcept
Definition node.hpp:58
size_t RemoveInputs(const util::HashSet< size_t > &indices)
Definition node.cpp:306
rvsdg::Region * region() const noexcept
Definition node.hpp:761
size_t ninputs() const noexcept
Definition node.hpp:609
size_t noutputs() const noexcept
Definition node.hpp:644
size_t RemoveOutputs(const util::HashSet< size_t > &indices)
Definition node.cpp:342
rvsdg::Region * region() const noexcept
Definition node.cpp:151
size_t index() const noexcept
Definition node.hpp:274
void divert_users(jlm::rvsdg::Output *new_origin)
Definition node.hpp:301
bool IsDead() const noexcept
Definition node.hpp:295
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
StructuralInput * input() const noexcept
Definition region.hpp:69
Represents the result of a region.
Definition region.hpp:120
StructuralOutput * output() const noexcept
Definition region.hpp:149
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
size_t RemoveResults(const util::HashSet< size_t > &indices)
Definition region.cpp:281
RegionArgument * argument(size_t index) const noexcept
Definition region.hpp:466
void copy(Region *target, SubstitutionMap &smap) const
Copy a region with substitutions.
Definition region.cpp:317
size_t RemoveArguments(const util::HashSet< size_t > &indices)
Definition region.cpp:213
size_t narguments() const noexcept
Definition region.hpp:460
StructuralNode * node() const noexcept
StructuralInput * addInput(std::unique_ptr< StructuralInput > input, bool notifyRegion)
StructuralOutput * addOutput(std::unique_ptr< StructuralOutput > input)
StructuralOutput * output(size_t index) const noexcept
StructuralInput * input(size_t index) const noexcept
StructuralNode * node() const noexcept
virtual std::string debug_string() const =0
virtual TypeKind Kind() const noexcept=0
Return the kind of this type.
size_type size() const noexcept
Iterator begin() noexcept
#define JLM_ASSERT(x)
Definition common.hpp:16
std::shared_ptr< const BundleType > get_mem_res_type(std::shared_ptr< const jlm::rvsdg::Type > dataType)
Definition hls.cpp:335
std::shared_ptr< const BundleType > get_mem_req_type(std::shared_ptr< const rvsdg::Type > elementType, bool write)
Definition hls.cpp:320
int JlmSize(const jlm::rvsdg::Type *type)
Definition hls.cpp:344
size_t GetPointerSizeInBits()
Definition hls.cpp:396
static void remove(Node *node)
Definition region.hpp:1035
TypeKind
The kinds of types supported in rvsdg.
Definition type.hpp:22
@ State
Designate a state type.
@ Value
Designate a value type.
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
void combineHashesWithSeed(std::size_t &seed, std::size_t hash, Args... args)
Definition Hash.hpp:45