Jlm
Loading...
Searching...
No Matches
hls.hpp
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#ifndef JLM_HLS_IR_HLS_HPP
7#define JLM_HLS_IR_HLS_HPP
8
10#include <jlm/llvm/ir/types.hpp>
11#include <jlm/rvsdg/control.hpp>
15#include <jlm/util/common.hpp>
16
17#include <memory>
18#include <utility>
19
20namespace jlm::hls
21{
25[[nodiscard]] size_t
27
28int
29JlmSize(const jlm::rvsdg::Type * type);
30
32{
33public:
35
37 size_t nalternatives,
38 const std::shared_ptr<const jlm::rvsdg::Type> & type,
39 bool loop)
41 { rvsdg::ControlType::Create(nalternatives), type },
42 { nalternatives, type }),
43 loop(loop)
44 {}
45
46 bool
47 operator==(const Operation & other) const noexcept override
48 {
49 auto ot = dynamic_cast<const BranchOperation *>(&other);
50 // check predicate and value
51 return ot && ot->loop == loop && *ot->argument(0) == *argument(0)
52 && *ot->result(0) == *result(0);
53 }
54
55 std::string
56 debug_string() const override
57 {
58 return "HLS_BRANCH";
59 }
60
61 [[nodiscard]] std::unique_ptr<Operation>
62 copy() const override
63 {
64 return std::make_unique<BranchOperation>(*this);
65 }
66
67 static std::vector<jlm::rvsdg::Output *>
68 create(jlm::rvsdg::Output & predicate, jlm::rvsdg::Output & value, bool loop = false)
69 {
70 auto ctl = std::dynamic_pointer_cast<const rvsdg::ControlType>(predicate.Type());
71 if (!ctl)
72 throw util::Error("Predicate needs to be a control type.");
73
75 { &predicate, &value },
76 ctl->nalternatives(),
77 value.Type(),
78 loop));
79 }
80
81 bool loop; // only used for dot output
82};
83
97{
98public:
100
107 ForkOperation(size_t nalternatives, const std::shared_ptr<const jlm::rvsdg::Type> & type)
108 : SimpleOperation({ type }, { nalternatives, type })
109 {}
110
119 size_t nalternatives,
120 const std::shared_ptr<const jlm::rvsdg::Type> & type,
121 bool isConstant)
122 : SimpleOperation({ type }, { nalternatives, type }),
123 IsConstant_(isConstant)
124 {}
125
126 bool
127 operator==(const Operation & other) const noexcept override
128 {
129 const auto forkOp = dynamic_cast<const ForkOperation *>(&other);
130 // check predicate and value
131 return forkOp && *forkOp->argument(0) == *argument(0) && forkOp->nresults() == nresults()
132 && forkOp->IsConstant() == IsConstant_;
133 }
134
139 std::string
140 debug_string() const override
141 {
142 return IsConstant() ? "HLS_CFORK" : "HLS_FORK";
143 }
144
145 [[nodiscard]] std::unique_ptr<Operation>
146 copy() const override
147 {
148 return std::make_unique<ForkOperation>(*this);
149 }
150
160 static std::vector<jlm::rvsdg::Output *>
161 create(size_t nalternatives, jlm::rvsdg::Output & value, bool isConstant = false)
162 {
163 return outputs(
164 &rvsdg::CreateOpNode<ForkOperation>({ &value }, nalternatives, value.Type(), isConstant));
165 }
166
176 static rvsdg::Node &
177 CreateNode(const size_t numResults, rvsdg::Output & operand, const bool isConstant = false)
178 {
179 return rvsdg::CreateOpNode<ForkOperation>({ &operand }, numResults, operand.Type(), isConstant);
180 }
181
188 [[nodiscard]] bool
190 {
191 return IsConstant_;
192 }
193
194private:
195 bool IsConstant_ = false;
196};
197
199{
200public:
202
204 size_t nalternatives,
205 const std::shared_ptr<const jlm::rvsdg::Type> & type,
206 bool discarding,
207 bool loop)
208 : SimpleOperation(create_typevector(nalternatives, type), { type }),
210 loop(loop)
211 {}
212
213 bool
214 operator==(const Operation & other) const noexcept override
215 {
216 const auto ot = dynamic_cast<const MuxOperation *>(&other);
217 // check predicate and value
218 return ot && *ot->argument(0) == *argument(0) && *ot->result(0) == *result(0)
219 && ot->discarding == discarding;
220 }
221
222 std::string
223 debug_string() const override
224 {
225 return discarding ? "HLS_DMUX" : "HLS_NDMUX";
226 }
227
228 [[nodiscard]] std::unique_ptr<Operation>
229 copy() const override
230 {
231 return std::make_unique<MuxOperation>(*this);
232 }
233
234 static std::vector<jlm::rvsdg::Output *>
236 jlm::rvsdg::Output & predicate,
237 const std::vector<jlm::rvsdg::Output *> & alternatives,
238 bool discarding,
239 bool loop = false)
240 {
241 if (alternatives.empty())
242 throw util::Error("Insufficient number of operands.");
243 auto ctl = std::dynamic_pointer_cast<const rvsdg::ControlType>(predicate.Type());
244 if (!ctl)
245 throw util::Error("Predicate needs to be a control type.");
246 if (alternatives.size() != ctl->nalternatives())
247 throw util::Error("Alternatives and predicate do not match.");
248
249 auto operands = std::vector<jlm::rvsdg::Output *>();
250 operands.push_back(&predicate);
251 operands.insert(operands.end(), alternatives.begin(), alternatives.end());
253 operands,
254 alternatives.size(),
255 alternatives.front()->Type(),
257 loop));
258 }
259
261 bool loop; // used only for dot output
262private:
263 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
264 create_typevector(size_t nalternatives, std::shared_ptr<const jlm::rvsdg::Type> type)
265 {
266 auto vec =
267 std::vector<std::shared_ptr<const jlm::rvsdg::Type>>(nalternatives + 1, std::move(type));
268 vec[0] = rvsdg::ControlType::Create(nalternatives);
269 return vec;
270 }
271};
272
274{
275public:
277
279 : SimpleOperation({ type }, {})
280 {}
281
282 bool
283 operator==(const Operation & other) const noexcept override
284 {
285 const auto ot = dynamic_cast<const SinkOperation *>(&other);
286 return ot && *ot->argument(0) == *argument(0);
287 }
288
289 std::string
290 debug_string() const override
291 {
292 return "HLS_SINK";
293 }
294
295 [[nodiscard]] std::unique_ptr<Operation>
296 copy() const override
297 {
298 return std::make_unique<SinkOperation>(*this);
299 }
300
301 static std::vector<jlm::rvsdg::Output *>
303 {
304 return outputs(&rvsdg::CreateOpNode<SinkOperation>({ &value }, value.Type()));
305 }
306};
307
309{
310public:
312
314 : SimpleOperation({ type }, { type })
315 {}
316
317 bool
318 operator==(const Operation & other) const noexcept override
319 {
320 const auto ot = dynamic_cast<const PredicateBufferOperation *>(&other);
321 return ot && *ot->result(0) == *result(0);
322 }
323
324 std::string
325 debug_string() const override
326 {
327 return "HLS_PRED_BUF";
328 }
329
330 [[nodiscard]] std::unique_ptr<Operation>
331 copy() const override
332 {
333 return std::make_unique<PredicateBufferOperation>(*this);
334 }
335
336 static std::vector<jlm::rvsdg::Output *>
338 {
339 auto ctl = std::dynamic_pointer_cast<const rvsdg::ControlType>(predicate.Type());
340 if (!ctl)
341 throw util::Error("Predicate needs to be a control type.");
342
344 }
345};
346
348{
349public:
351
354 const std::shared_ptr<const jlm::rvsdg::Type> & type)
355 : SimpleOperation({ ctltype, type }, { type })
356 {}
357
358 bool
359 operator==(const Operation & other) const noexcept override
360 {
361 const auto ot = dynamic_cast<const LoopConstantBufferOperation *>(&other);
362 return ot && *ot->result(0) == *result(0) && *ot->argument(0) == *argument(0);
363 }
364
365 std::string
366 debug_string() const override
367 {
368 return "HLS_LOOP_CONST_BUF";
369 }
370
371 [[nodiscard]] std::unique_ptr<Operation>
372 copy() const override
373 {
374 return std::make_unique<LoopConstantBufferOperation>(*this);
375 }
376
377 static std::vector<jlm::rvsdg::Output *>
379 {
380 auto ctl = std::dynamic_pointer_cast<const rvsdg::ControlType>(predicate.Type());
381 if (!ctl)
382 throw util::Error("Predicate needs to be a control type.");
383
385 { &predicate, &value },
386 ctl,
387 value.Type()));
388 }
389};
390
392{
393public:
395
397 const std::shared_ptr<const jlm::rvsdg::Type> & type,
398 size_t capacity,
399 bool pass_through)
400 : SimpleOperation({ type }, { type }),
401 Capacity_(capacity),
403 {}
404
405 [[nodiscard]] std::size_t
407 {
408 return Capacity_;
409 }
410
411 [[nodiscard]] bool
413 {
414 return IsPassThrough_;
415 }
416
417 bool
418 operator==(const Operation & other) const noexcept override
419 {
420 const auto ot = dynamic_cast<const BufferOperation *>(&other);
421 return ot && ot->Capacity() == Capacity() && ot->IsPassThrough() == IsPassThrough()
422 && *ot->result(0) == *result(0);
423 }
424
425 [[nodiscard]] std::string
426 debug_string() const override
427 {
428 return util::strfmt("HLS_BUF_", (IsPassThrough() ? "P_" : ""), Capacity());
429 }
430
431 [[nodiscard]] std::unique_ptr<Operation>
432 copy() const override
433 {
434 return std::make_unique<BufferOperation>(*this);
435 }
436
437 static std::vector<jlm::rvsdg::Output *>
438 create(jlm::rvsdg::Output & value, size_t capacity, bool pass_through = false)
439 {
440 return outputs(
441 &rvsdg::CreateOpNode<BufferOperation>({ &value }, value.Type(), capacity, pass_through));
442 }
443
444private:
445 std::size_t Capacity_;
447};
448
450{
451public:
453
455
456 std::string
457 debug_string() const override
458 {
459 return "trigger";
460 };
461
462 bool
463 operator==(const Type & other) const noexcept override
464 {
466 };
467
468 [[nodiscard]] std::size_t
470
471 rvsdg::TypeKind
473
475 Create();
476};
477
479{
480public:
482
484 : SimpleOperation({ TriggerType::Create(), type }, { type })
485 {}
486
487 bool
488 operator==(const Operation & other) const noexcept override
489 {
490 const auto ot = dynamic_cast<const TriggerOperation *>(&other);
491 // check predicate and value
492 return ot && *ot->argument(1) == *argument(1) && *ot->result(0) == *result(0);
493 }
494
495 std::string
496 debug_string() const override
497 {
498 return "HLS_TRIGGER";
499 }
500
501 [[nodiscard]] std::unique_ptr<Operation>
502 copy() const override
503 {
504 return std::make_unique<TriggerOperation>(*this);
505 }
506
507 static std::vector<jlm::rvsdg::Output *>
509 {
510 if (!rvsdg::is<TriggerType>(tg.Type()))
511 throw util::Error("Trigger needs to be a TriggerType.");
512
513 return outputs(&rvsdg::CreateOpNode<TriggerOperation>({ &tg, &value }, value.Type()));
514 }
515};
516
518{
519 size_t _id;
520
521public:
522 ~PrintOperation() noexcept override;
523
524 explicit PrintOperation(const std::shared_ptr<const rvsdg::Type> & type)
525 : SimpleOperation({ type }, { type })
526 {
527 static size_t common_id{ 0 };
528 _id = common_id++;
529 }
530
531 bool
532 operator==(const Operation &) const noexcept override
533 {
534 // print nodes are intentionally distinct
535 return false;
536 }
537
538 std::string
539 debug_string() const override
540 {
541 return util::strfmt("HLS_PRINT_", _id);
542 }
543
544 size_t
545 id() const
546 {
547 return _id;
548 }
549
550 [[nodiscard]] std::unique_ptr<Operation>
551 copy() const override
552 {
553 return std::make_unique<PrintOperation>(*this);
554 }
555
556 static std::vector<jlm::rvsdg::Output *>
558 {
559 return outputs(&rvsdg::CreateOpNode<PrintOperation>({ &value }, value.Type()));
560 }
561};
562
564{
565public:
566 ~LoopOperation() noexcept override;
567
568 std::string
569 debug_string() const override
570 {
571 return "HLS_LOOP";
572 }
573
574 [[nodiscard]] std::unique_ptr<Operation>
575 copy() const override
576 {
577 return std::make_unique<LoopOperation>(*this);
578 }
579};
580
581class BackEdgeArgument;
582class BackEdgeResult;
583class LoopNode;
584
589{
590 friend LoopNode;
591
593 rvsdg::Region & region,
595 const std::shared_ptr<const rvsdg::Type> type)
596 : rvsdg::RegionArgument(&region, &input, std::move(type))
597 {}
598
599public:
600 ~EntryArgument() noexcept override;
601
603 Copy(rvsdg::Region & region, rvsdg::StructuralInput * input) const override;
604
605 // FIXME: This should not be public, but we currently still have some transformations that use
606 // this one. Make it eventually private.
607 static EntryArgument &
608 Create(
609 rvsdg::Region & region,
610 rvsdg::StructuralInput & input,
611 const std::shared_ptr<const rvsdg::Type> type)
612 {
613 std::unique_ptr<EntryArgument> argument(new EntryArgument(region, input, std::move(type)));
614 return static_cast<EntryArgument &>(region.addArgument(std::move(argument)));
615 }
616};
617
619{
620 friend LoopNode;
622
623 BackEdgeArgument(rvsdg::Region * region, const std::shared_ptr<const jlm::rvsdg::Type> & type)
624 : rvsdg::RegionArgument(region, nullptr, type),
625 result_(nullptr)
626 {}
627
628public:
629 ~BackEdgeArgument() noexcept override = default;
630
632 result()
633 {
634 return result_;
635 }
636
638 Copy(rvsdg::Region & region, rvsdg::StructuralInput * input) const override;
639
640 static BackEdgeArgument &
641 create(rvsdg::Region * region, std::shared_ptr<const jlm::rvsdg::Type> type)
642 {
643 std::unique_ptr<BackEdgeArgument> argument(new BackEdgeArgument(region, std::move(type)));
644 return static_cast<BackEdgeArgument &>(region->addArgument(std::move(argument)));
645 }
646
648};
649
651{
652 friend LoopNode;
654
656 : rvsdg::RegionResult(origin->region(), origin, nullptr, origin->Type()),
657 argument_(nullptr)
658 {}
659
660public:
661 ~BackEdgeResult() override = default;
662
664 argument() const
665 {
666 return argument_;
667 }
668
670 Copy(rvsdg::Output & origin, rvsdg::StructuralOutput * output) const override;
671
672 static BackEdgeResult &
674 {
675 std::unique_ptr<BackEdgeResult> result(new BackEdgeResult(origin));
676 return static_cast<BackEdgeResult &>(origin->region()->addResult(std::move(result)));
677 }
678
680};
681
686{
687 friend LoopNode;
688
690
691public:
692 ~ExitResult() noexcept override;
693
694 ExitResult &
695 Copy(rvsdg::Output & origin, rvsdg::StructuralOutput * output) const override;
696
697 // FIXME: This should not be public, but we currently still have some transformations that use
698 // this one. Make it eventually private.
699 static ExitResult &
700 Create(rvsdg::Output & origin, rvsdg::StructuralOutput & output)
701 {
702 std::unique_ptr<RegionResult> result(new ExitResult(origin, output));
703 return static_cast<ExitResult &>(origin.region()->addResult(std::move(result)));
704 }
705};
706
708{
709public:
710 ~LoopNode() noexcept override = default;
711
712private:
713 explicit LoopNode(rvsdg::Region * parent)
714 : StructuralNode(parent, 1)
715 {}
716
717public:
718 [[nodiscard]] const rvsdg::Operation &
719 GetOperation() const noexcept override;
720
721 static LoopNode *
722 create(rvsdg::Region * parent, bool init = true);
723
724 rvsdg::Region *
725 subregion() const noexcept
726 {
727 return StructuralNode::subregion(0);
728 }
729
730 [[nodiscard]] rvsdg::RegionResult *
731 predicate() const noexcept
732 {
733 auto result = subregion()->result(0);
734 JLM_ASSERT(rvsdg::is<const rvsdg::ControlType>(result->Type()));
735 return result;
736 }
737
739 GetPredicateBuffer() const noexcept
740 {
741 return *PredicateBuffer_;
742 }
743
744 void
745 set_predicate(jlm::rvsdg::Output * p);
746
748 add_backedge(std::shared_ptr<const jlm::rvsdg::Type> type);
749
770 AddLoopVar(rvsdg::Output * origin, rvsdg::Output ** buffer = nullptr);
771
779 addLoopConstant(rvsdg::Output * origin);
780
789 addResponseInput(rvsdg::Output * origin);
790
799 addRequestOutput(rvsdg::Output * origin);
800
805 void
806 removeLoopOutput(rvsdg::StructuralOutput * output);
807
812 void
813 removeLoopInput(rvsdg::StructuralInput * input);
814
815 LoopNode *
816 copy(rvsdg::Region * region, rvsdg::SubstitutionMap & smap) const override;
817
818private:
819 rvsdg::Output * PredicateBuffer_{};
820};
821
823{
824public:
825 ~BundleType() noexcept override;
826
827 explicit BundleType(
828 const std::vector<std::pair<std::string, std::shared_ptr<const Type>>> elements)
829 : elements_(std::move(elements))
830 {}
831
832 BundleType(const BundleType &) = default;
833
834 BundleType(BundleType &&) = delete;
835
836 BundleType &
837 operator=(const BundleType &) = delete;
838
839 BundleType &
840 operator=(BundleType &&) = delete;
841
842 bool
843 operator==(const jlm::rvsdg::Type & other) const noexcept override
844 {
845 auto type = dynamic_cast<const BundleType *>(&other);
846 // TODO: better comparison?
847 if (!type || type->elements_.size() != elements_.size())
848 {
849 return false;
850 }
851 for (size_t i = 0; i < elements_.size(); ++i)
852 {
853 if (type->elements_.at(i).first != elements_.at(i).first
854 || *type->elements_.at(i).second != *elements_.at(i).second)
855 {
856 return false;
857 }
858 }
859 return true;
860 };
861
862 [[nodiscard]] std::size_t
863 ComputeHash() const noexcept override;
864
865 rvsdg::TypeKind
866 Kind() const noexcept override;
867
868 std::shared_ptr<const jlm::rvsdg::Type>
869 get_element_type(std::string element) const
870 {
871 for (size_t i = 0; i < elements_.size(); ++i)
872 {
873 if (elements_.at(i).first == element)
874 {
875 return elements_.at(i).second;
876 }
877 }
878 // TODO: do something different?
879 return {};
880 }
881
882 [[nodiscard]] std::string
883 debug_string() const override
884 {
885 return "bundle";
886 };
887
888 // private:
889 // TODO: fix memory leak
890 const std::vector<std::pair<std::string, std::shared_ptr<const jlm::rvsdg::Type>>> elements_;
891};
892
893std::shared_ptr<const BundleType>
894get_mem_req_type(std::shared_ptr<const rvsdg::Type> elementType, bool write);
895
896std::shared_ptr<const BundleType>
897get_mem_res_type(std::shared_ptr<const jlm::rvsdg::Type> dataType);
898
900{
901public:
902 ~LoadOperation() noexcept override;
903
904 LoadOperation(const std::shared_ptr<const rvsdg::Type> & pointeeType, size_t numStates)
906 CreateInTypes(pointeeType, numStates),
907 CreateOutTypes(pointeeType, numStates))
908 {}
909
910 bool
911 operator==(const Operation & other) const noexcept override
912 {
913 auto ot = dynamic_cast<const LoadOperation *>(&other);
914 // check predicate and value
915 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
916 }
917
918 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
919 CreateInTypes(std::shared_ptr<const rvsdg::Type> pointeeType, size_t numStates)
920 {
921 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(
922 1,
923 llvm::PointerType::Create()); // addr
924 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
925 numStates,
926 llvm::MemoryStateType::Create());
927 types.insert(types.end(), states.begin(), states.end());
928 types.emplace_back(std::move(pointeeType)); // result
929 return types;
930 }
931
932 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
933 CreateOutTypes(std::shared_ptr<const rvsdg::Type> pointeeType, size_t numStates)
934 {
935 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(1, std::move(pointeeType));
936 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
937 numStates,
938 llvm::MemoryStateType::Create());
939 types.insert(types.end(), states.begin(), states.end());
940 types.emplace_back(llvm::PointerType::Create()); // addr
941 return types;
942 }
943
944 std::string
945 debug_string() const override
946 {
947 return "HLS_LOAD_" + argument(narguments() - 1)->debug_string();
948 }
949
950 [[nodiscard]] std::unique_ptr<Operation>
951 copy() const override
952 {
953 return std::make_unique<LoadOperation>(*this);
954 }
955
956 static std::vector<jlm::rvsdg::Output *>
958 jlm::rvsdg::Output & addr,
959 const std::vector<jlm::rvsdg::Output *> & states,
960 jlm::rvsdg::Output & load_result)
961 {
962 std::vector<jlm::rvsdg::Output *> inputs;
963 inputs.push_back(&addr);
964 inputs.insert(inputs.end(), states.begin(), states.end());
965 inputs.push_back(&load_result);
966 return outputs(&rvsdg::CreateOpNode<LoadOperation>(inputs, load_result.Type(), states.size()));
967 }
968
969 [[nodiscard]] const llvm::PointerType &
970 GetPointerType() const noexcept
971 {
972 return *util::assertedCast<const llvm::PointerType>(argument(0).get());
973 }
974
975 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
976 GetLoadedType() const noexcept
977 {
978 return result(0);
979 }
980};
981
983{
984public:
985 ~AddressQueueOperation() noexcept override;
986
988 const std::shared_ptr<const llvm::PointerType> & pointerType,
989 size_t capacity,
990 bool combinatorial)
991 : SimpleOperation(CreateInTypes(pointerType), CreateOutTypes(pointerType)),
992 combinatorial(combinatorial),
993 capacity(capacity)
994 {}
995
996 bool
997 operator==(const Operation & other) const noexcept override
998 {
999 auto ot = dynamic_cast<const AddressQueueOperation *>(&other);
1000 // check predicate and value
1001 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1002 }
1003
1004 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1005 CreateInTypes(std::shared_ptr<const llvm::PointerType> pointerType)
1006 {
1007 // check, enq
1008 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(2, std::move(pointerType));
1009 types.emplace_back(llvm::MemoryStateType::Create()); // deq
1010 return types;
1011 }
1012
1013 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1014 CreateOutTypes(std::shared_ptr<const llvm::PointerType> pointerType)
1015 {
1016 return { std::move(pointerType) };
1017 }
1018
1019 std::string
1020 debug_string() const override
1021 {
1022 if (combinatorial)
1023 {
1024 return "HLS_ADDR_QUEUE_COMB_" + argument(narguments() - 1)->debug_string();
1025 }
1026 return "HLS_ADDR_QUEUE_" + argument(narguments() - 1)->debug_string();
1027 }
1028
1029 [[nodiscard]] std::unique_ptr<Operation>
1030 copy() const override
1031 {
1032 return std::make_unique<AddressQueueOperation>(*this);
1033 }
1034
1035 static jlm::rvsdg::Output *
1038 jlm::rvsdg::Output & enq,
1039 jlm::rvsdg::Output & deq,
1040 bool combinatorial,
1041 size_t capacity = 10)
1042 {
1043 return rvsdg::CreateOpNode<AddressQueueOperation>(
1044 { &check, &enq, &deq },
1045 std::dynamic_pointer_cast<const llvm::PointerType>(check.Type()),
1046 capacity,
1047 combinatorial)
1048 .output(0);
1049 }
1050
1052 size_t capacity;
1053};
1054
1056{
1057public:
1058 ~StateGateOperation() noexcept override;
1059
1060 StateGateOperation(const std::shared_ptr<const rvsdg::Type> & type, const size_t numStates)
1061 : SimpleOperation(CreateInOutTypes(type, numStates), CreateInOutTypes(type, numStates))
1062 {}
1063
1064 bool
1065 operator==(const Operation & other) const noexcept override
1066 {
1067 auto ot = dynamic_cast<const StateGateOperation *>(&other);
1068 // check predicate and value
1069 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1070 }
1071
1072 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1073 CreateInOutTypes(const std::shared_ptr<const jlm::rvsdg::Type> & type, size_t numStates)
1074 {
1075 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(1, type);
1076 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
1077 numStates,
1078 llvm::MemoryStateType::Create());
1079 types.insert(types.end(), states.begin(), states.end());
1080 return types;
1081 }
1082
1083 std::string
1084 debug_string() const override
1085 {
1086 return "HLS_STATE_GATE_" + argument(narguments() - 1)->debug_string();
1087 }
1088
1089 [[nodiscard]] std::unique_ptr<Operation>
1090 copy() const override
1091 {
1092 return std::make_unique<StateGateOperation>(*this);
1093 }
1094
1095 static std::vector<jlm::rvsdg::Output *>
1096 create(jlm::rvsdg::Output & addr, const std::vector<jlm::rvsdg::Output *> & states)
1097 {
1098 std::vector<jlm::rvsdg::Output *> inputs;
1099 inputs.push_back(&addr);
1100 inputs.insert(inputs.end(), states.begin(), states.end());
1101 return outputs(&rvsdg::CreateOpNode<StateGateOperation>(inputs, addr.Type(), states.size()));
1102 }
1103};
1104
1106{
1107public:
1108 ~DecoupledLoadOperation() noexcept override;
1109
1110 DecoupledLoadOperation(const std::shared_ptr<const rvsdg::Type> & pointeeType, size_t capacity)
1111 : SimpleOperation(CreateInTypes(pointeeType), CreateOutTypes(pointeeType)),
1112 capacity(capacity)
1113 {}
1114
1115 bool
1116 operator==(const Operation & other) const noexcept override
1117 {
1118 auto ot = dynamic_cast<const DecoupledLoadOperation *>(&other);
1119 // check predicate and value
1120 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1121 }
1122
1123 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1124 CreateInTypes(std::shared_ptr<const rvsdg::Type> pointeeType)
1125 {
1126 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types = {
1127 llvm::PointerType::Create(),
1128 pointeeType // result
1129 };
1130 return types;
1131 }
1132
1133 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1134 CreateOutTypes(std::shared_ptr<const rvsdg::Type> pointeeType)
1135 {
1136 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types = {
1137 pointeeType,
1138 llvm::PointerType::Create() // addr
1139 };
1140 return types;
1141 }
1142
1143 std::string
1144 debug_string() const override
1145 {
1146 return "HLS_DEC_LOAD_" + std::to_string(capacity) + "_"
1147 + argument(narguments() - 1)->debug_string();
1148 }
1149
1150 [[nodiscard]] std::unique_ptr<Operation>
1151 copy() const override
1152 {
1153 return std::make_unique<DecoupledLoadOperation>(*this);
1154 }
1155
1156 static std::vector<jlm::rvsdg::Output *>
1157 create(jlm::rvsdg::Output & addr, jlm::rvsdg::Output & load_result, size_t capacity)
1158 {
1159 std::vector<jlm::rvsdg::Output *> inputs;
1160 inputs.push_back(&addr);
1161 inputs.push_back(&load_result);
1162 JLM_ASSERT(capacity >= 1);
1163 return outputs(
1164 &rvsdg::CreateOpNode<DecoupledLoadOperation>(inputs, load_result.Type(), capacity));
1165 }
1166
1167 [[nodiscard]] const llvm::PointerType &
1168 GetPointerType() const noexcept
1169 {
1170 return *util::assertedCast<const llvm::PointerType>(argument(0).get());
1171 }
1172
1173 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
1174 GetLoadedType() const noexcept
1175 {
1176 return result(0);
1177 }
1178
1179 size_t capacity;
1180};
1181
1183{
1184public:
1185 ~MemoryResponseOperation() noexcept override;
1186
1188 const std::vector<std::shared_ptr<const rvsdg::Type>> & output_types,
1189 int in_width)
1190 : SimpleOperation(CreateInTypes(in_width), CreateOutTypes(output_types))
1191 {}
1192
1193 bool
1194 operator==(const Operation & other) const noexcept override
1195 {
1196 auto ot = dynamic_cast<const MemoryResponseOperation *>(&other);
1197 // check predicate and value
1198 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1199 }
1200
1201 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1202 CreateInTypes(int in_width)
1203 {
1204 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types;
1205 types.emplace_back(get_mem_res_type(jlm::rvsdg::BitType::Create(in_width)));
1206 return types;
1207 }
1208
1209 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1210 CreateOutTypes(const std::vector<std::shared_ptr<const rvsdg::Type>> & output_types)
1211 {
1212 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types;
1213 types.reserve(output_types.size());
1214 for (auto outputType : output_types)
1215 {
1216 types.emplace_back(outputType);
1217 }
1218 return types;
1219 }
1220
1221 std::string
1222 debug_string() const override
1223 {
1224 return "HLS_MEM_RESP";
1225 }
1226
1227 [[nodiscard]] std::unique_ptr<Operation>
1228 copy() const override
1229 {
1230 return std::make_unique<MemoryResponseOperation>(*this);
1231 }
1232
1233 static std::vector<jlm::rvsdg::Output *>
1235 rvsdg::Output & result,
1236 const std::vector<std::shared_ptr<const rvsdg::Type>> & output_types,
1237 int in_width)
1238 {
1239 return outputs(
1240 &rvsdg::CreateOpNode<MemoryResponseOperation>({ &result }, output_types, in_width));
1241 }
1242};
1243
1245{
1246public:
1247 ~MemoryRequestOperation() noexcept override = default;
1248
1250 const std::vector<std::shared_ptr<const rvsdg::Type>> & load_types,
1251 const std::vector<std::shared_ptr<const rvsdg::Type>> & store_types)
1253 CreateInTypes(load_types, store_types),
1254 CreateOutTypes(load_types, store_types))
1255 {
1256 for (auto loadType : load_types)
1257 {
1258 LoadTypes_.emplace_back(loadType);
1259 }
1260 for (auto storeType : store_types)
1261 {
1262 StoreTypes_.emplace_back(storeType);
1263 }
1264 }
1265
1267
1268 bool
1269 operator==(const Operation & other) const noexcept override
1270 {
1271 auto ot = dynamic_cast<const MemoryRequestOperation *>(&other);
1272 // check predicate and value
1273 return ot && ot->narguments() == narguments()
1274 && (ot->narguments() == 0 || (*ot->argument(1) == *argument(1)))
1275 && ot->narguments() == narguments();
1276 }
1277
1278 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1280 const std::vector<std::shared_ptr<const rvsdg::Type>> & load_types,
1281 const std::vector<std::shared_ptr<const rvsdg::Type>> & store_types)
1282 {
1283 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types;
1284 for (size_t i = 0; i < load_types.size(); i++)
1285 {
1286 types.emplace_back(llvm::PointerType::Create()); // addr
1287 }
1288 for (auto storeType : store_types)
1289 {
1290 types.emplace_back(llvm::PointerType::Create()); // addr
1291 types.emplace_back(storeType); // data
1292 }
1293 return types;
1294 }
1295
1296 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1298 const std::vector<std::shared_ptr<const rvsdg::Type>> & load_types,
1299 const std::vector<std::shared_ptr<const rvsdg::Type>> & store_types)
1300 {
1301 int max_width = 0;
1302 for (auto tp : load_types)
1303 {
1304 auto sz = JlmSize(tp.get());
1305 max_width = sz > max_width ? sz : max_width;
1306 }
1307 for (auto tp : store_types)
1308 {
1309 auto sz = JlmSize(tp.get());
1310 max_width = sz > max_width ? sz : max_width;
1311 }
1312 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types;
1313 types.emplace_back(
1314 get_mem_req_type(jlm::rvsdg::BitType::Create(max_width), !store_types.empty()));
1315 return types;
1316 }
1317
1318 std::string
1319 debug_string() const override
1320 {
1321 return "HLS_MEM_REQ";
1322 }
1323
1324 [[nodiscard]] std::unique_ptr<Operation>
1325 copy() const override
1326 {
1327 return std::make_unique<MemoryRequestOperation>(*this);
1328 }
1329
1330 static std::vector<jlm::rvsdg::Output *>
1332 const std::vector<jlm::rvsdg::Output *> & load_operands,
1333 const std::vector<std::shared_ptr<const rvsdg::Type>> & loadTypes,
1334 const std::vector<jlm::rvsdg::Output *> & store_operands,
1335 rvsdg::Region *)
1336 {
1337 // Stores have both addr and data operand
1338 // But we are only interested in the data operand type
1339 JLM_ASSERT(store_operands.size() % 2 == 0);
1340 std::vector<std::shared_ptr<const rvsdg::Type>> storeTypes;
1341 for (size_t i = 1; i < store_operands.size(); i += 2)
1342 {
1343 storeTypes.push_back(store_operands[i]->Type());
1344 }
1345 std::vector operands(load_operands);
1346 operands.insert(operands.end(), store_operands.begin(), store_operands.end());
1347 return outputs(&rvsdg::CreateOpNode<MemoryRequestOperation>(operands, loadTypes, storeTypes));
1348 }
1349
1350 size_t
1352 {
1353 return LoadTypes_.size();
1354 }
1355
1356 const std::vector<std::shared_ptr<const rvsdg::Type>> *
1358 {
1359 return &LoadTypes_;
1360 }
1361
1362 const std::vector<std::shared_ptr<const rvsdg::Type>> *
1364 {
1365 return &StoreTypes_;
1366 }
1367
1368private:
1369 std::vector<std::shared_ptr<const rvsdg::Type>> LoadTypes_;
1370 std::vector<std::shared_ptr<const rvsdg::Type>> StoreTypes_;
1371};
1372
1374{
1375public:
1376 ~StoreOperation() noexcept override;
1377
1378 StoreOperation(const std::shared_ptr<const rvsdg::Type> & pointeeType, size_t numStates)
1380 CreateInTypes(pointeeType, numStates),
1381 CreateOutTypes(pointeeType, numStates))
1382 {}
1383
1384 bool
1385 operator==(const Operation & other) const noexcept override
1386 {
1387 auto ot = dynamic_cast<const StoreOperation *>(&other);
1388 // check predicate and value
1389 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1390 }
1391
1392 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1393 CreateInTypes(const std::shared_ptr<const rvsdg::Type> & pointeeType, size_t numStates)
1394 {
1395 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(
1396 { llvm::PointerType::Create(), pointeeType });
1397 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
1398 numStates + 1,
1399 llvm::MemoryStateType::Create());
1400 types.insert(types.end(), states.begin(), states.end());
1401 return types;
1402 }
1403
1404 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1405 CreateOutTypes(const std::shared_ptr<const rvsdg::Type> & pointeeType, size_t numStates)
1406 {
1407 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(
1408 numStates,
1409 llvm::MemoryStateType::Create());
1410 types.emplace_back(llvm::PointerType::Create()); // addr
1411 types.emplace_back(pointeeType); // data
1412 return types;
1413 }
1414
1415 std::string
1416 debug_string() const override
1417 {
1418 return "HLS_STORE_" + argument(narguments() - 1)->debug_string();
1419 }
1420
1421 [[nodiscard]] std::unique_ptr<Operation>
1422 copy() const override
1423 {
1424 return std::make_unique<StoreOperation>(*this);
1425 }
1426
1427 static std::vector<jlm::rvsdg::Output *>
1429 jlm::rvsdg::Output & addr,
1430 jlm::rvsdg::Output & value,
1431 const std::vector<jlm::rvsdg::Output *> & states,
1432 jlm::rvsdg::Output & resp)
1433 {
1434 std::vector<jlm::rvsdg::Output *> inputs;
1435 inputs.push_back(&addr);
1436 inputs.push_back(&value);
1437 inputs.insert(inputs.end(), states.begin(), states.end());
1438 inputs.push_back(&resp);
1439 return outputs(&rvsdg::CreateOpNode<StoreOperation>(inputs, value.Type(), states.size()));
1440 }
1441
1442 [[nodiscard]] const llvm::PointerType &
1443 GetPointerType() const noexcept
1444 {
1445 return *util::assertedCast<const llvm::PointerType>(argument(0).get());
1446 }
1447
1448 [[nodiscard]] const rvsdg::Type &
1449 GetStoredType() const noexcept
1450 {
1451 return *argument(1).get();
1452 }
1453};
1454
1456{
1457public:
1458 ~LocalMemoryOperation() noexcept override;
1459
1460 explicit LocalMemoryOperation(std::shared_ptr<const llvm::ArrayType> at)
1461 : SimpleOperation({}, CreateOutTypes(std::move(at)))
1462 {}
1463
1464 bool
1465 operator==(const Operation &) const noexcept override
1466 {
1467 return false;
1468 }
1469
1470 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1471 CreateOutTypes(std::shared_ptr<const llvm::ArrayType> at)
1472 {
1473 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(2, std::move(at));
1474 return types;
1475 }
1476
1477 std::string
1478 debug_string() const override
1479 {
1480 return "HLS_LOCAL_MEM_" + result(0)->debug_string();
1481 }
1482
1483 [[nodiscard]] std::unique_ptr<Operation>
1484 copy() const override
1485 {
1486 return std::make_unique<LocalMemoryOperation>(*this);
1487 }
1488
1489 static std::vector<jlm::rvsdg::Output *>
1490 create(std::shared_ptr<const llvm::ArrayType> at, rvsdg::Region * region)
1491 {
1492 return outputs(&rvsdg::CreateOpNode<LocalMemoryOperation>(*region, std::move(at)));
1493 }
1494};
1495
1497{
1498public:
1500
1501 LocalMemoryResponseOperation(const std::shared_ptr<const llvm::ArrayType> & at, size_t resp_count)
1502 : SimpleOperation({ at }, CreateOutTypes(at, resp_count))
1503 {}
1504
1505 bool
1506 operator==(const Operation & other) const noexcept override
1507 {
1508 auto ot = dynamic_cast<const LocalMemoryResponseOperation *>(&other);
1509 // check predicate and value
1510 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1511 }
1512
1513 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1514 CreateOutTypes(const std::shared_ptr<const jlm::llvm::ArrayType> & at, size_t resp_count)
1515 {
1516 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(resp_count, at->GetElementType());
1517 return types;
1518 }
1519
1520 std::string
1521 debug_string() const override
1522 {
1523 return "HLS_LOCAL_MEM_RESP";
1524 }
1525
1526 [[nodiscard]] std::unique_ptr<Operation>
1527 copy() const override
1528 {
1529 return std::make_unique<LocalMemoryResponseOperation>(*this);
1530 }
1531
1532 static std::vector<jlm::rvsdg::Output *>
1533 create(jlm::rvsdg::Output & mem, size_t resp_count)
1534 {
1535 return outputs(&rvsdg::CreateOpNode<LocalMemoryResponseOperation>(
1536 { &mem },
1537 std::dynamic_pointer_cast<const llvm::ArrayType>(mem.Type()),
1538 resp_count));
1539 }
1540};
1541
1543{
1544public:
1545 ~LocalLoadOperation() noexcept override;
1546
1547 LocalLoadOperation(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1548 : SimpleOperation(CreateInTypes(valuetype, numStates), CreateOutTypes(valuetype, numStates))
1549 {}
1550
1551 bool
1552 operator==(const Operation & other) const noexcept override
1553 {
1554 auto ot = dynamic_cast<const LocalLoadOperation *>(&other);
1555 // check predicate and value
1556 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1557 }
1558
1559 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1560 CreateInTypes(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1561 {
1562 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(1, jlm::rvsdg::BitType::Create(64));
1563 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
1564 numStates,
1565 llvm::MemoryStateType::Create());
1566 types.insert(types.end(), states.begin(), states.end());
1567 types.emplace_back(valuetype); // result
1568 return types;
1569 }
1570
1571 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1572 CreateOutTypes(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1573 {
1574 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(1, valuetype);
1575 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
1576 numStates,
1577 llvm::MemoryStateType::Create());
1578 types.insert(types.end(), states.begin(), states.end());
1579 types.emplace_back(jlm::rvsdg::BitType::Create(64)); // addr
1580 return types;
1581 }
1582
1583 std::string
1584 debug_string() const override
1585 {
1586 return "HLS_LOCAL_LOAD_" + argument(narguments() - 1)->debug_string();
1587 }
1588
1589 [[nodiscard]] std::unique_ptr<Operation>
1590 copy() const override
1591 {
1592 return std::make_unique<LocalLoadOperation>(*this);
1593 }
1594
1595 static std::vector<jlm::rvsdg::Output *>
1597 jlm::rvsdg::Output & index,
1598 const std::vector<jlm::rvsdg::Output *> & states,
1599 jlm::rvsdg::Output & load_result)
1600 {
1601 std::vector<jlm::rvsdg::Output *> inputs;
1602 inputs.push_back(&index);
1603 inputs.insert(inputs.end(), states.begin(), states.end());
1604 inputs.push_back(&load_result);
1605 return outputs(
1606 &rvsdg::CreateOpNode<LocalLoadOperation>(inputs, load_result.Type(), states.size()));
1607 }
1608
1609 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
1610 GetLoadedType() const noexcept
1611 {
1612 return result(0);
1613 }
1614};
1615
1617{
1618public:
1619 ~LocalStoreOperation() noexcept override;
1620
1621 LocalStoreOperation(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1622 : SimpleOperation(CreateInTypes(valuetype, numStates), CreateOutTypes(valuetype, numStates))
1623 {}
1624
1625 bool
1626 operator==(const Operation & other) const noexcept override
1627 {
1628 auto ot = dynamic_cast<const LocalStoreOperation *>(&other);
1629 // check predicate and value
1630 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1631 }
1632
1633 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1634 CreateInTypes(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1635 {
1636 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(
1637 { jlm::rvsdg::BitType::Create(64), valuetype });
1638 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
1639 numStates,
1640 llvm::MemoryStateType::Create());
1641 types.insert(types.end(), states.begin(), states.end());
1642 return types;
1643 }
1644
1645 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1646 CreateOutTypes(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1647 {
1648 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(
1649 numStates,
1650 llvm::MemoryStateType::Create());
1651 types.emplace_back(jlm::rvsdg::BitType::Create(64)); // addr
1652 types.emplace_back(valuetype); // data
1653 return types;
1654 }
1655
1656 std::string
1657 debug_string() const override
1658 {
1659 return "HLS_LOCAL_STORE_" + argument(narguments() - 1)->debug_string();
1660 }
1661
1662 [[nodiscard]] std::unique_ptr<Operation>
1663 copy() const override
1664 {
1665 return std::make_unique<LocalStoreOperation>(*this);
1666 }
1667
1668 static std::vector<jlm::rvsdg::Output *>
1670 jlm::rvsdg::Output & index,
1671 jlm::rvsdg::Output & value,
1672 const std::vector<jlm::rvsdg::Output *> & states)
1673 {
1674 std::vector<jlm::rvsdg::Output *> inputs;
1675 inputs.push_back(&index);
1676 inputs.push_back(&value);
1677 inputs.insert(inputs.end(), states.begin(), states.end());
1678 return outputs(&rvsdg::CreateOpNode<LocalStoreOperation>(inputs, value.Type(), states.size()));
1679 }
1680
1681 [[nodiscard]] const jlm::rvsdg::Type &
1682 GetStoredType() const noexcept
1683 {
1684 return *argument(1).get();
1685 }
1686};
1687
1689{
1690public:
1691 ~LocalMemoryRequestOperation() noexcept override;
1692
1694 const std::shared_ptr<const llvm::ArrayType> & at,
1695 size_t load_cnt,
1696 size_t store_cnt)
1697 : SimpleOperation(CreateInTypes(at, load_cnt, store_cnt), {})
1698 {}
1699
1700 bool
1701 operator==(const Operation & other) const noexcept override
1702 {
1703 auto ot = dynamic_cast<const LocalMemoryRequestOperation *>(&other);
1704 // check predicate and value
1705 return ot && ot->narguments() == narguments()
1706 && (ot->narguments() == 0 || (*ot->argument(1) == *argument(1)))
1707 && ot->narguments() == narguments();
1708 }
1709
1710 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1712 const std::shared_ptr<const llvm::ArrayType> & at,
1713 size_t load_cnt,
1714 size_t store_cnt)
1715 {
1716 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(1, at);
1717 for (size_t i = 0; i < load_cnt; ++i)
1718 {
1719 types.emplace_back(jlm::rvsdg::BitType::Create(64)); // addr
1720 }
1721 for (size_t i = 0; i < store_cnt; ++i)
1722 {
1723 types.emplace_back(jlm::rvsdg::BitType::Create(64)); // addr
1724 types.emplace_back(at->GetElementType()); // data
1725 }
1726 return types;
1727 }
1728
1729 std::string
1730 debug_string() const override
1731 {
1732 return "HLS_LOCAL_MEM_REQ";
1733 }
1734
1735 [[nodiscard]] std::unique_ptr<Operation>
1736 copy() const override
1737 {
1738 return std::make_unique<LocalMemoryRequestOperation>(*this);
1739 }
1740
1741 static std::vector<jlm::rvsdg::Output *>
1743 jlm::rvsdg::Output & mem,
1744 const std::vector<jlm::rvsdg::Output *> & load_operands,
1745 const std::vector<jlm::rvsdg::Output *> & store_operands)
1746 {
1747 JLM_ASSERT(store_operands.size() % 2 == 0);
1748 std::vector operands(1, &mem);
1749 operands.insert(operands.end(), load_operands.begin(), load_operands.end());
1750 operands.insert(operands.end(), store_operands.begin(), store_operands.end());
1751 return outputs(&rvsdg::CreateOpNode<LocalMemoryRequestOperation>(
1752 operands,
1753 std::dynamic_pointer_cast<const llvm::ArrayType>(mem.Type()),
1754 load_operands.size(),
1755 store_operands.size() / 2));
1756 }
1757};
1758
1759}
1760#endif // JLM_HLS_IR_HLS_HPP
static void check(const jlm::llvm::DominatorTreeNode *dnode, const jlm::llvm::ControlFlowGraphNode *node, const std::unordered_set< const jlm::llvm::ControlFlowGraphNode * > &children)
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:997
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(std::shared_ptr< const llvm::PointerType > pointerType)
Definition hls.hpp:1014
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1030
~AddressQueueOperation() noexcept override
std::string debug_string() const override
Definition hls.hpp:1020
static jlm::rvsdg::Output * create(jlm::rvsdg::Output &check, jlm::rvsdg::Output &enq, jlm::rvsdg::Output &deq, bool combinatorial, size_t capacity=10)
Definition hls.hpp:1036
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(std::shared_ptr< const llvm::PointerType > pointerType)
Definition hls.hpp:1005
BackEdgeResult * result_
Definition hls.hpp:647
~BackEdgeArgument() noexcept override=default
BackEdgeArgument(rvsdg::Region *region, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition hls.hpp:623
static BackEdgeArgument & create(rvsdg::Region *region, std::shared_ptr< const jlm::rvsdg::Type > type)
Definition hls.hpp:641
BackEdgeResult(rvsdg::Output *origin)
Definition hls.hpp:655
~BackEdgeResult() override=default
BackEdgeArgument * argument_
Definition hls.hpp:679
BackEdgeArgument * argument() const
Definition hls.hpp:664
static BackEdgeResult & create(jlm::rvsdg::Output *origin)
Definition hls.hpp:673
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:62
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &predicate, jlm::rvsdg::Output &value, bool loop=false)
Definition hls.hpp:68
std::string debug_string() const override
Definition hls.hpp:56
~BranchOperation() noexcept override
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:47
~BufferOperation() noexcept override
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:418
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &value, size_t capacity, bool pass_through=false)
Definition hls.hpp:438
std::string debug_string() const override
Definition hls.hpp:426
std::size_t Capacity_
Definition hls.hpp:445
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:432
std::size_t Capacity() const noexcept
Definition hls.hpp:406
bool IsPassThrough() const noexcept
Definition hls.hpp:412
BundleType & operator=(BundleType &&)=delete
std::string debug_string() const override
Definition hls.hpp:883
BundleType(const BundleType &)=default
const std::vector< std::pair< std::string, std::shared_ptr< const jlm::rvsdg::Type > > > elements_
Definition hls.hpp:890
~BundleType() noexcept override
BundleType & operator=(const BundleType &)=delete
BundleType(BundleType &&)=delete
bool operator==(const jlm::rvsdg::Type &other) const noexcept override
Definition hls.hpp:843
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(std::shared_ptr< const rvsdg::Type > pointeeType)
Definition hls.hpp:1124
~DecoupledLoadOperation() noexcept override
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &addr, jlm::rvsdg::Output &load_result, size_t capacity)
Definition hls.hpp:1157
std::string debug_string() const override
Definition hls.hpp:1144
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1116
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1151
std::shared_ptr< const rvsdg::Type > GetLoadedType() const noexcept
Definition hls.hpp:1174
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(std::shared_ptr< const rvsdg::Type > pointeeType)
Definition hls.hpp:1134
const llvm::PointerType & GetPointerType() const noexcept
Definition hls.hpp:1168
~EntryArgument() noexcept override
EntryArgument(rvsdg::Region &region, rvsdg::StructuralInput &input, const std::shared_ptr< const rvsdg::Type > type)
Definition hls.hpp:592
~ExitResult() noexcept override
ForkOperation(size_t nalternatives, const std::shared_ptr< const jlm::rvsdg::Type > &type, bool isConstant)
Definition hls.hpp:118
static std::vector< jlm::rvsdg::Output * > create(size_t nalternatives, jlm::rvsdg::Output &value, bool isConstant=false)
Definition hls.hpp:161
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:146
static rvsdg::Node & CreateNode(const size_t numResults, rvsdg::Output &operand, const bool isConstant=false)
Definition hls.hpp:177
std::string debug_string() const override
Definition hls.hpp:140
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:127
~ForkOperation() noexcept override
bool IsConstant() const noexcept
Definition hls.hpp:189
std::shared_ptr< const rvsdg::Type > GetLoadedType() const noexcept
Definition hls.hpp:976
const llvm::PointerType & GetPointerType() const noexcept
Definition hls.hpp:970
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:911
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(std::shared_ptr< const rvsdg::Type > pointeeType, size_t numStates)
Definition hls.hpp:933
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:951
~LoadOperation() noexcept override
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(std::shared_ptr< const rvsdg::Type > pointeeType, size_t numStates)
Definition hls.hpp:919
std::string debug_string() const override
Definition hls.hpp:945
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &addr, const std::vector< jlm::rvsdg::Output * > &states, jlm::rvsdg::Output &load_result)
Definition hls.hpp:957
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1552
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &index, const std::vector< jlm::rvsdg::Output * > &states, jlm::rvsdg::Output &load_result)
Definition hls.hpp:1596
std::shared_ptr< const rvsdg::Type > GetLoadedType() const noexcept
Definition hls.hpp:1610
std::string debug_string() const override
Definition hls.hpp:1584
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(const std::shared_ptr< const jlm::rvsdg::Type > &valuetype, size_t numStates)
Definition hls.hpp:1572
~LocalLoadOperation() noexcept override
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(const std::shared_ptr< const jlm::rvsdg::Type > &valuetype, size_t numStates)
Definition hls.hpp:1560
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1590
bool operator==(const Operation &) const noexcept override
Definition hls.hpp:1465
static std::vector< jlm::rvsdg::Output * > create(std::shared_ptr< const llvm::ArrayType > at, rvsdg::Region *region)
Definition hls.hpp:1490
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1484
std::string debug_string() const override
Definition hls.hpp:1478
~LocalMemoryOperation() noexcept override
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(std::shared_ptr< const llvm::ArrayType > at)
Definition hls.hpp:1471
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1736
~LocalMemoryRequestOperation() noexcept override
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &mem, const std::vector< jlm::rvsdg::Output * > &load_operands, const std::vector< jlm::rvsdg::Output * > &store_operands)
Definition hls.hpp:1742
std::string debug_string() const override
Definition hls.hpp:1730
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1701
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(const std::shared_ptr< const llvm::ArrayType > &at, size_t load_cnt, size_t store_cnt)
Definition hls.hpp:1711
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1506
~LocalMemoryResponseOperation() noexcept override
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1527
std::string debug_string() const override
Definition hls.hpp:1521
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &mem, size_t resp_count)
Definition hls.hpp:1533
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(const std::shared_ptr< const jlm::llvm::ArrayType > &at, size_t resp_count)
Definition hls.hpp:1514
~LocalStoreOperation() noexcept override
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1663
std::string debug_string() const override
Definition hls.hpp:1657
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &index, jlm::rvsdg::Output &value, const std::vector< jlm::rvsdg::Output * > &states)
Definition hls.hpp:1669
const jlm::rvsdg::Type & GetStoredType() const noexcept
Definition hls.hpp:1682
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1626
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(const std::shared_ptr< const jlm::rvsdg::Type > &valuetype, size_t numStates)
Definition hls.hpp:1634
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(const std::shared_ptr< const jlm::rvsdg::Type > &valuetype, size_t numStates)
Definition hls.hpp:1646
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &predicate, jlm::rvsdg::Output &value)
Definition hls.hpp:378
std::string debug_string() const override
Definition hls.hpp:366
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:359
~LoopConstantBufferOperation() noexcept override
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:372
rvsdg::RegionResult * predicate() const noexcept
Definition hls.hpp:731
rvsdg::Output & GetPredicateBuffer() const noexcept
Definition hls.hpp:739
~LoopNode() noexcept override=default
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:575
~LoopOperation() noexcept override
const std::vector< std::shared_ptr< const rvsdg::Type > > * GetLoadTypes() const
Definition hls.hpp:1357
const std::vector< std::shared_ptr< const rvsdg::Type > > * GetStoreTypes() const
Definition hls.hpp:1363
~MemoryRequestOperation() noexcept override=default
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(const std::vector< std::shared_ptr< const rvsdg::Type > > &load_types, const std::vector< std::shared_ptr< const rvsdg::Type > > &store_types)
Definition hls.hpp:1279
static std::vector< jlm::rvsdg::Output * > create(const std::vector< jlm::rvsdg::Output * > &load_operands, const std::vector< std::shared_ptr< const rvsdg::Type > > &loadTypes, const std::vector< jlm::rvsdg::Output * > &store_operands, rvsdg::Region *)
Definition hls.hpp:1331
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(const std::vector< std::shared_ptr< const rvsdg::Type > > &load_types, const std::vector< std::shared_ptr< const rvsdg::Type > > &store_types)
Definition hls.hpp:1297
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1269
MemoryRequestOperation(const MemoryRequestOperation &other)=default
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1325
std::vector< std::shared_ptr< const rvsdg::Type > > LoadTypes_
Definition hls.hpp:1369
std::string debug_string() const override
Definition hls.hpp:1319
std::vector< std::shared_ptr< const rvsdg::Type > > StoreTypes_
Definition hls.hpp:1370
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1228
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(int in_width)
Definition hls.hpp:1202
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(const std::vector< std::shared_ptr< const rvsdg::Type > > &output_types)
Definition hls.hpp:1210
static std::vector< jlm::rvsdg::Output * > create(rvsdg::Output &result, const std::vector< std::shared_ptr< const rvsdg::Type > > &output_types, int in_width)
Definition hls.hpp:1234
std::string debug_string() const override
Definition hls.hpp:1222
~MemoryResponseOperation() noexcept override
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1194
~MuxOperation() noexcept override
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > create_typevector(size_t nalternatives, std::shared_ptr< const jlm::rvsdg::Type > type)
Definition hls.hpp:264
std::string debug_string() const override
Definition hls.hpp:223
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:229
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:214
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
~PredicateBufferOperation() noexcept override
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:331
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:318
std::string debug_string() const override
Definition hls.hpp:325
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &predicate)
Definition hls.hpp:337
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &value)
Definition hls.hpp:557
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:551
bool operator==(const Operation &) const noexcept override
Definition hls.hpp:532
~PrintOperation() noexcept override
std::string debug_string() const override
Definition hls.hpp:539
size_t id() const
Definition hls.hpp:545
~SinkOperation() noexcept override
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:283
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:296
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &value)
Definition hls.hpp:302
std::string debug_string() const override
Definition hls.hpp:290
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1065
~StateGateOperation() noexcept override
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInOutTypes(const std::shared_ptr< const jlm::rvsdg::Type > &type, size_t numStates)
Definition hls.hpp:1073
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &addr, const std::vector< jlm::rvsdg::Output * > &states)
Definition hls.hpp:1096
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1090
std::string debug_string() const override
Definition hls.hpp:1084
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(const std::shared_ptr< const rvsdg::Type > &pointeeType, size_t numStates)
Definition hls.hpp:1405
~StoreOperation() noexcept override
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1422
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1385
const rvsdg::Type & GetStoredType() const noexcept
Definition hls.hpp:1449
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(const std::shared_ptr< const rvsdg::Type > &pointeeType, size_t numStates)
Definition hls.hpp:1393
std::string debug_string() const override
Definition hls.hpp:1416
const llvm::PointerType & GetPointerType() const noexcept
Definition hls.hpp:1443
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &addr, jlm::rvsdg::Output &value, const std::vector< jlm::rvsdg::Output * > &states, jlm::rvsdg::Output &resp)
Definition hls.hpp:1428
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:488
std::string debug_string() const override
Definition hls.hpp:496
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:502
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &tg, jlm::rvsdg::Output &value)
Definition hls.hpp:508
~TriggerOperation() noexcept override
std::size_t ComputeHash() const noexcept override
Definition hls.cpp:60
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
std::string debug_string() const override
Definition hls.hpp:457
~TriggerType() noexcept override
bool operator==(const Type &other) const noexcept override
Definition hls.hpp:463
PointerType class.
Definition types.hpp:25
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
Definition type.cpp:45
static std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
Definition control.cpp:50
rvsdg::Region * region() const noexcept
Definition node.cpp:151
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
Represents the argument of a region.
Definition region.hpp:41
Represents the result of a region.
Definition region.hpp:120
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
RegionArgument & addArgument(std::unique_ptr< RegionArgument > argument)
Definition region.cpp:179
RegionResult & addResult(std::unique_ptr< RegionResult > result)
Definition region.cpp:265
const std::shared_ptr< const rvsdg::Type > & argument(size_t index) const noexcept
Definition operation.cpp:23
const std::shared_ptr< const rvsdg::Type > & result(size_t index) const noexcept
Definition operation.cpp:36
size_t nresults() const noexcept
Definition operation.cpp:30
size_t narguments() const noexcept
Definition operation.cpp:17
#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 std::vector< jlm::rvsdg::Output * > operands(const Node *node)
Definition node.hpp:1049
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)
Definition node.hpp:1058
TypeKind
The kinds of types supported in rvsdg.
Definition type.hpp:22
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
static std::string strfmt(Args... args)
Definition strfmt.hpp:35