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:
732
747
762
763 [[nodiscard]] const rvsdg::Operation &
764 GetOperation() const noexcept override;
765
767 mapInput(const rvsdg::Input & input);
768
769 ExitVar
770 mapOutput(const rvsdg::Output & output);
771
772 std::variant<EntryVar, BackEdgeVar>
773 mapArgument(const rvsdg::Output & argument);
774
775 std::variant<ExitVar, BackEdgeVar>
776 mapResult(const rvsdg::Input & result);
777
778 std::vector<EntryVar>
779 getEntryVars();
780
781 std::vector<ExitVar>
782 getExitVars();
783
784 std::vector<BackEdgeVar>
785 getBackEdgeVars();
786
787 void
788 removeEntryVars(std::vector<EntryVar> vars);
789
790 void
791 removeExitVars(std::vector<ExitVar> vars);
792
793 void
794 removeBackEdgeVars(std::vector<BackEdgeVar> vars);
795
796 static LoopNode *
797 create(rvsdg::Region * parent);
798
799 rvsdg::Region *
800 subregion() const noexcept
801 {
802 return StructuralNode::subregion(0);
803 }
804
805 [[nodiscard]] rvsdg::RegionResult *
806 predicate() const noexcept
807 {
808 auto result = subregion()->result(0);
809 JLM_ASSERT(rvsdg::is<const rvsdg::ControlType>(result->Type()));
810 return result;
811 }
812
814 GetPredicateBuffer() const noexcept
815 {
816 return *PredicateBuffer_;
817 }
818
819 void
820 set_predicate(jlm::rvsdg::Output * p);
821
823 add_backedge(std::shared_ptr<const jlm::rvsdg::Type> type);
824
845 AddLoopVar(rvsdg::Output * origin, rvsdg::Output ** buffer = nullptr);
846
854 addLoopConstant(rvsdg::Output * origin);
855
864 addResponseInput(rvsdg::Output * origin);
865
874 addRequestOutput(rvsdg::Output * origin);
875
876 LoopNode *
877 copy(rvsdg::Region * region, rvsdg::SubstitutionMap & smap) const override;
878
879private:
880 rvsdg::Output * PredicateBuffer_{};
881};
882
884{
885public:
886 ~BundleType() noexcept override;
887
888 explicit BundleType(
889 const std::vector<std::pair<std::string, std::shared_ptr<const Type>>> elements)
890 : elements_(std::move(elements))
891 {}
892
893 BundleType(const BundleType &) = default;
894
895 BundleType(BundleType &&) = delete;
896
897 BundleType &
898 operator=(const BundleType &) = delete;
899
900 BundleType &
901 operator=(BundleType &&) = delete;
902
903 bool
904 operator==(const jlm::rvsdg::Type & other) const noexcept override
905 {
906 auto type = dynamic_cast<const BundleType *>(&other);
907 // TODO: better comparison?
908 if (!type || type->elements_.size() != elements_.size())
909 {
910 return false;
911 }
912 for (size_t i = 0; i < elements_.size(); ++i)
913 {
914 if (type->elements_.at(i).first != elements_.at(i).first
915 || *type->elements_.at(i).second != *elements_.at(i).second)
916 {
917 return false;
918 }
919 }
920 return true;
921 };
922
923 [[nodiscard]] std::size_t
924 ComputeHash() const noexcept override;
925
926 rvsdg::TypeKind
927 Kind() const noexcept override;
928
929 std::shared_ptr<const jlm::rvsdg::Type>
930 get_element_type(std::string element) const
931 {
932 for (size_t i = 0; i < elements_.size(); ++i)
933 {
934 if (elements_.at(i).first == element)
935 {
936 return elements_.at(i).second;
937 }
938 }
939 // TODO: do something different?
940 return {};
941 }
942
943 [[nodiscard]] std::string
944 debug_string() const override
945 {
946 return "bundle";
947 };
948
949 // private:
950 // TODO: fix memory leak
951 const std::vector<std::pair<std::string, std::shared_ptr<const jlm::rvsdg::Type>>> elements_;
952};
953
954std::shared_ptr<const BundleType>
955get_mem_req_type(std::shared_ptr<const rvsdg::Type> elementType, bool write);
956
957std::shared_ptr<const BundleType>
958get_mem_res_type(std::shared_ptr<const jlm::rvsdg::Type> dataType);
959
961{
962public:
963 ~LoadOperation() noexcept override;
964
965 LoadOperation(const std::shared_ptr<const rvsdg::Type> & pointeeType, size_t numStates)
967 CreateInTypes(pointeeType, numStates),
968 CreateOutTypes(pointeeType, numStates))
969 {}
970
971 bool
972 operator==(const Operation & other) const noexcept override
973 {
974 auto ot = dynamic_cast<const LoadOperation *>(&other);
975 // check predicate and value
976 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
977 }
978
979 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
980 CreateInTypes(std::shared_ptr<const rvsdg::Type> pointeeType, size_t numStates)
981 {
982 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(
983 1,
984 llvm::PointerType::Create()); // addr
985 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
986 numStates,
987 llvm::MemoryStateType::Create());
988 types.insert(types.end(), states.begin(), states.end());
989 types.emplace_back(std::move(pointeeType)); // result
990 return types;
991 }
992
993 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
994 CreateOutTypes(std::shared_ptr<const rvsdg::Type> pointeeType, size_t numStates)
995 {
996 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(1, std::move(pointeeType));
997 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
998 numStates,
999 llvm::MemoryStateType::Create());
1000 types.insert(types.end(), states.begin(), states.end());
1001 types.emplace_back(llvm::PointerType::Create()); // addr
1002 return types;
1003 }
1004
1005 std::string
1006 debug_string() const override
1007 {
1008 return "HLS_LOAD_" + argument(narguments() - 1)->debug_string();
1009 }
1010
1011 [[nodiscard]] std::unique_ptr<Operation>
1012 copy() const override
1013 {
1014 return std::make_unique<LoadOperation>(*this);
1015 }
1016
1017 static std::vector<jlm::rvsdg::Output *>
1019 jlm::rvsdg::Output & addr,
1020 const std::vector<jlm::rvsdg::Output *> & states,
1021 jlm::rvsdg::Output & load_result)
1022 {
1023 std::vector<jlm::rvsdg::Output *> inputs;
1024 inputs.push_back(&addr);
1025 inputs.insert(inputs.end(), states.begin(), states.end());
1026 inputs.push_back(&load_result);
1027 return outputs(&rvsdg::CreateOpNode<LoadOperation>(inputs, load_result.Type(), states.size()));
1028 }
1029
1030 [[nodiscard]] const llvm::PointerType &
1031 GetPointerType() const noexcept
1032 {
1033 return *util::assertedCast<const llvm::PointerType>(argument(0).get());
1034 }
1035
1036 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
1037 GetLoadedType() const noexcept
1038 {
1039 return result(0);
1040 }
1041};
1042
1044{
1045public:
1046 ~AddressQueueOperation() noexcept override;
1047
1049 const std::shared_ptr<const llvm::PointerType> & pointerType,
1050 size_t capacity,
1051 bool combinatorial)
1052 : SimpleOperation(CreateInTypes(pointerType), CreateOutTypes(pointerType)),
1053 combinatorial(combinatorial),
1054 capacity(capacity)
1055 {}
1056
1057 bool
1058 operator==(const Operation & other) const noexcept override
1059 {
1060 auto ot = dynamic_cast<const AddressQueueOperation *>(&other);
1061 // check predicate and value
1062 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1063 }
1064
1065 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1066 CreateInTypes(std::shared_ptr<const llvm::PointerType> pointerType)
1067 {
1068 // check, enq
1069 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(2, std::move(pointerType));
1070 types.emplace_back(llvm::MemoryStateType::Create()); // deq
1071 return types;
1072 }
1073
1074 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1075 CreateOutTypes(std::shared_ptr<const llvm::PointerType> pointerType)
1076 {
1077 return { std::move(pointerType) };
1078 }
1079
1080 std::string
1081 debug_string() const override
1082 {
1083 if (combinatorial)
1084 {
1085 return "HLS_ADDR_QUEUE_COMB_" + argument(narguments() - 1)->debug_string();
1086 }
1087 return "HLS_ADDR_QUEUE_" + argument(narguments() - 1)->debug_string();
1088 }
1089
1090 [[nodiscard]] std::unique_ptr<Operation>
1091 copy() const override
1092 {
1093 return std::make_unique<AddressQueueOperation>(*this);
1094 }
1095
1096 static jlm::rvsdg::Output *
1099 jlm::rvsdg::Output & enq,
1100 jlm::rvsdg::Output & deq,
1101 bool combinatorial,
1102 size_t capacity = 10)
1103 {
1104 return rvsdg::CreateOpNode<AddressQueueOperation>(
1105 { &check, &enq, &deq },
1106 std::dynamic_pointer_cast<const llvm::PointerType>(check.Type()),
1107 capacity,
1108 combinatorial)
1109 .output(0);
1110 }
1111
1113 size_t capacity;
1114};
1115
1117{
1118public:
1119 ~StateGateOperation() noexcept override;
1120
1121 StateGateOperation(const std::shared_ptr<const rvsdg::Type> & type, const size_t numStates)
1122 : SimpleOperation(CreateInOutTypes(type, numStates), CreateInOutTypes(type, numStates))
1123 {}
1124
1125 bool
1126 operator==(const Operation & other) const noexcept override
1127 {
1128 auto ot = dynamic_cast<const StateGateOperation *>(&other);
1129 // check predicate and value
1130 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1131 }
1132
1133 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1134 CreateInOutTypes(const std::shared_ptr<const jlm::rvsdg::Type> & type, size_t numStates)
1135 {
1136 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(1, type);
1137 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
1138 numStates,
1139 llvm::MemoryStateType::Create());
1140 types.insert(types.end(), states.begin(), states.end());
1141 return types;
1142 }
1143
1144 std::string
1145 debug_string() const override
1146 {
1147 return "HLS_STATE_GATE_" + argument(narguments() - 1)->debug_string();
1148 }
1149
1150 [[nodiscard]] std::unique_ptr<Operation>
1151 copy() const override
1152 {
1153 return std::make_unique<StateGateOperation>(*this);
1154 }
1155
1156 static std::vector<jlm::rvsdg::Output *>
1157 create(jlm::rvsdg::Output & addr, const std::vector<jlm::rvsdg::Output *> & states)
1158 {
1159 std::vector<jlm::rvsdg::Output *> inputs;
1160 inputs.push_back(&addr);
1161 inputs.insert(inputs.end(), states.begin(), states.end());
1162 return outputs(&rvsdg::CreateOpNode<StateGateOperation>(inputs, addr.Type(), states.size()));
1163 }
1164};
1165
1167{
1168public:
1169 ~DecoupledLoadOperation() noexcept override;
1170
1171 DecoupledLoadOperation(const std::shared_ptr<const rvsdg::Type> & pointeeType, size_t capacity)
1172 : SimpleOperation(CreateInTypes(pointeeType), CreateOutTypes(pointeeType)),
1173 capacity(capacity)
1174 {}
1175
1176 bool
1177 operator==(const Operation & other) const noexcept override
1178 {
1179 auto ot = dynamic_cast<const DecoupledLoadOperation *>(&other);
1180 // check predicate and value
1181 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1182 }
1183
1184 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1185 CreateInTypes(std::shared_ptr<const rvsdg::Type> pointeeType)
1186 {
1187 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types = {
1188 llvm::PointerType::Create(),
1189 pointeeType // result
1190 };
1191 return types;
1192 }
1193
1194 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1195 CreateOutTypes(std::shared_ptr<const rvsdg::Type> pointeeType)
1196 {
1197 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types = {
1198 pointeeType,
1199 llvm::PointerType::Create() // addr
1200 };
1201 return types;
1202 }
1203
1204 std::string
1205 debug_string() const override
1206 {
1207 return "HLS_DEC_LOAD_" + std::to_string(capacity) + "_"
1208 + argument(narguments() - 1)->debug_string();
1209 }
1210
1211 [[nodiscard]] std::unique_ptr<Operation>
1212 copy() const override
1213 {
1214 return std::make_unique<DecoupledLoadOperation>(*this);
1215 }
1216
1217 static std::vector<jlm::rvsdg::Output *>
1218 create(jlm::rvsdg::Output & addr, jlm::rvsdg::Output & load_result, size_t capacity)
1219 {
1220 std::vector<jlm::rvsdg::Output *> inputs;
1221 inputs.push_back(&addr);
1222 inputs.push_back(&load_result);
1223 JLM_ASSERT(capacity >= 1);
1224 return outputs(
1225 &rvsdg::CreateOpNode<DecoupledLoadOperation>(inputs, load_result.Type(), capacity));
1226 }
1227
1228 [[nodiscard]] const llvm::PointerType &
1229 GetPointerType() const noexcept
1230 {
1231 return *util::assertedCast<const llvm::PointerType>(argument(0).get());
1232 }
1233
1234 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
1235 GetLoadedType() const noexcept
1236 {
1237 return result(0);
1238 }
1239
1240 size_t capacity;
1241};
1242
1244{
1245public:
1246 ~MemoryResponseOperation() noexcept override;
1247
1249 const std::vector<std::shared_ptr<const rvsdg::Type>> & output_types,
1250 int in_width)
1251 : SimpleOperation(CreateInTypes(in_width), CreateOutTypes(output_types))
1252 {}
1253
1254 bool
1255 operator==(const Operation & other) const noexcept override
1256 {
1257 auto ot = dynamic_cast<const MemoryResponseOperation *>(&other);
1258 // check predicate and value
1259 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1260 }
1261
1262 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1263 CreateInTypes(int in_width)
1264 {
1265 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types;
1266 types.emplace_back(get_mem_res_type(jlm::rvsdg::BitType::Create(in_width)));
1267 return types;
1268 }
1269
1270 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1271 CreateOutTypes(const std::vector<std::shared_ptr<const rvsdg::Type>> & output_types)
1272 {
1273 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types;
1274 types.reserve(output_types.size());
1275 for (auto outputType : output_types)
1276 {
1277 types.emplace_back(outputType);
1278 }
1279 return types;
1280 }
1281
1282 std::string
1283 debug_string() const override
1284 {
1285 return "HLS_MEM_RESP";
1286 }
1287
1288 [[nodiscard]] std::unique_ptr<Operation>
1289 copy() const override
1290 {
1291 return std::make_unique<MemoryResponseOperation>(*this);
1292 }
1293
1294 static std::vector<jlm::rvsdg::Output *>
1296 rvsdg::Output & result,
1297 const std::vector<std::shared_ptr<const rvsdg::Type>> & output_types,
1298 int in_width)
1299 {
1300 return outputs(
1301 &rvsdg::CreateOpNode<MemoryResponseOperation>({ &result }, output_types, in_width));
1302 }
1303};
1304
1306{
1307public:
1308 ~MemoryRequestOperation() noexcept override = default;
1309
1311 const std::vector<std::shared_ptr<const rvsdg::Type>> & load_types,
1312 const std::vector<std::shared_ptr<const rvsdg::Type>> & store_types)
1314 CreateInTypes(load_types, store_types),
1315 CreateOutTypes(load_types, store_types))
1316 {
1317 for (auto loadType : load_types)
1318 {
1319 LoadTypes_.emplace_back(loadType);
1320 }
1321 for (auto storeType : store_types)
1322 {
1323 StoreTypes_.emplace_back(storeType);
1324 }
1325 }
1326
1328
1329 bool
1330 operator==(const Operation & other) const noexcept override
1331 {
1332 auto ot = dynamic_cast<const MemoryRequestOperation *>(&other);
1333 // check predicate and value
1334 return ot && ot->narguments() == narguments()
1335 && (ot->narguments() == 0 || (*ot->argument(1) == *argument(1)))
1336 && ot->narguments() == narguments();
1337 }
1338
1339 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1341 const std::vector<std::shared_ptr<const rvsdg::Type>> & load_types,
1342 const std::vector<std::shared_ptr<const rvsdg::Type>> & store_types)
1343 {
1344 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types;
1345 for (size_t i = 0; i < load_types.size(); i++)
1346 {
1347 types.emplace_back(llvm::PointerType::Create()); // addr
1348 }
1349 for (auto storeType : store_types)
1350 {
1351 types.emplace_back(llvm::PointerType::Create()); // addr
1352 types.emplace_back(storeType); // data
1353 }
1354 return types;
1355 }
1356
1357 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1359 const std::vector<std::shared_ptr<const rvsdg::Type>> & load_types,
1360 const std::vector<std::shared_ptr<const rvsdg::Type>> & store_types)
1361 {
1362 int max_width = 0;
1363 for (auto tp : load_types)
1364 {
1365 auto sz = JlmSize(tp.get());
1366 max_width = sz > max_width ? sz : max_width;
1367 }
1368 for (auto tp : store_types)
1369 {
1370 auto sz = JlmSize(tp.get());
1371 max_width = sz > max_width ? sz : max_width;
1372 }
1373 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types;
1374 types.emplace_back(
1375 get_mem_req_type(jlm::rvsdg::BitType::Create(max_width), !store_types.empty()));
1376 return types;
1377 }
1378
1379 std::string
1380 debug_string() const override
1381 {
1382 return "HLS_MEM_REQ";
1383 }
1384
1385 [[nodiscard]] std::unique_ptr<Operation>
1386 copy() const override
1387 {
1388 return std::make_unique<MemoryRequestOperation>(*this);
1389 }
1390
1391 static std::vector<jlm::rvsdg::Output *>
1393 const std::vector<jlm::rvsdg::Output *> & load_operands,
1394 const std::vector<std::shared_ptr<const rvsdg::Type>> & loadTypes,
1395 const std::vector<jlm::rvsdg::Output *> & store_operands,
1396 rvsdg::Region *)
1397 {
1398 // Stores have both addr and data operand
1399 // But we are only interested in the data operand type
1400 JLM_ASSERT(store_operands.size() % 2 == 0);
1401 std::vector<std::shared_ptr<const rvsdg::Type>> storeTypes;
1402 for (size_t i = 1; i < store_operands.size(); i += 2)
1403 {
1404 storeTypes.push_back(store_operands[i]->Type());
1405 }
1406 std::vector operands(load_operands);
1407 operands.insert(operands.end(), store_operands.begin(), store_operands.end());
1408 return outputs(&rvsdg::CreateOpNode<MemoryRequestOperation>(operands, loadTypes, storeTypes));
1409 }
1410
1411 size_t
1413 {
1414 return LoadTypes_.size();
1415 }
1416
1417 const std::vector<std::shared_ptr<const rvsdg::Type>> *
1419 {
1420 return &LoadTypes_;
1421 }
1422
1423 const std::vector<std::shared_ptr<const rvsdg::Type>> *
1425 {
1426 return &StoreTypes_;
1427 }
1428
1429private:
1430 std::vector<std::shared_ptr<const rvsdg::Type>> LoadTypes_;
1431 std::vector<std::shared_ptr<const rvsdg::Type>> StoreTypes_;
1432};
1433
1435{
1436public:
1437 ~StoreOperation() noexcept override;
1438
1439 StoreOperation(const std::shared_ptr<const rvsdg::Type> & pointeeType, size_t numStates)
1441 CreateInTypes(pointeeType, numStates),
1442 CreateOutTypes(pointeeType, numStates))
1443 {}
1444
1445 bool
1446 operator==(const Operation & other) const noexcept override
1447 {
1448 auto ot = dynamic_cast<const StoreOperation *>(&other);
1449 // check predicate and value
1450 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1451 }
1452
1453 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1454 CreateInTypes(const std::shared_ptr<const rvsdg::Type> & pointeeType, size_t numStates)
1455 {
1456 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(
1457 { llvm::PointerType::Create(), pointeeType });
1458 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
1459 numStates + 1,
1460 llvm::MemoryStateType::Create());
1461 types.insert(types.end(), states.begin(), states.end());
1462 return types;
1463 }
1464
1465 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1466 CreateOutTypes(const std::shared_ptr<const rvsdg::Type> & pointeeType, size_t numStates)
1467 {
1468 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(
1469 numStates,
1470 llvm::MemoryStateType::Create());
1471 types.emplace_back(llvm::PointerType::Create()); // addr
1472 types.emplace_back(pointeeType); // data
1473 return types;
1474 }
1475
1476 std::string
1477 debug_string() const override
1478 {
1479 return "HLS_STORE_" + argument(narguments() - 1)->debug_string();
1480 }
1481
1482 [[nodiscard]] std::unique_ptr<Operation>
1483 copy() const override
1484 {
1485 return std::make_unique<StoreOperation>(*this);
1486 }
1487
1488 static std::vector<jlm::rvsdg::Output *>
1490 jlm::rvsdg::Output & addr,
1491 jlm::rvsdg::Output & value,
1492 const std::vector<jlm::rvsdg::Output *> & states,
1493 jlm::rvsdg::Output & resp)
1494 {
1495 std::vector<jlm::rvsdg::Output *> inputs;
1496 inputs.push_back(&addr);
1497 inputs.push_back(&value);
1498 inputs.insert(inputs.end(), states.begin(), states.end());
1499 inputs.push_back(&resp);
1500 return outputs(&rvsdg::CreateOpNode<StoreOperation>(inputs, value.Type(), states.size()));
1501 }
1502
1503 [[nodiscard]] const llvm::PointerType &
1504 GetPointerType() const noexcept
1505 {
1506 return *util::assertedCast<const llvm::PointerType>(argument(0).get());
1507 }
1508
1509 [[nodiscard]] const rvsdg::Type &
1510 GetStoredType() const noexcept
1511 {
1512 return *argument(1).get();
1513 }
1514};
1515
1517{
1518public:
1519 ~LocalMemoryOperation() noexcept override;
1520
1521 explicit LocalMemoryOperation(std::shared_ptr<const llvm::ArrayType> at)
1522 : SimpleOperation({}, CreateOutTypes(std::move(at)))
1523 {}
1524
1525 bool
1526 operator==(const Operation &) const noexcept override
1527 {
1528 return false;
1529 }
1530
1531 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1532 CreateOutTypes(std::shared_ptr<const llvm::ArrayType> at)
1533 {
1534 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(2, std::move(at));
1535 return types;
1536 }
1537
1538 std::string
1539 debug_string() const override
1540 {
1541 return "HLS_LOCAL_MEM_" + result(0)->debug_string();
1542 }
1543
1544 [[nodiscard]] std::unique_ptr<Operation>
1545 copy() const override
1546 {
1547 return std::make_unique<LocalMemoryOperation>(*this);
1548 }
1549
1550 static std::vector<jlm::rvsdg::Output *>
1551 create(std::shared_ptr<const llvm::ArrayType> at, rvsdg::Region * region)
1552 {
1553 return outputs(&rvsdg::CreateOpNode<LocalMemoryOperation>(*region, std::move(at)));
1554 }
1555};
1556
1558{
1559public:
1561
1562 LocalMemoryResponseOperation(const std::shared_ptr<const llvm::ArrayType> & at, size_t resp_count)
1563 : SimpleOperation({ at }, CreateOutTypes(at, resp_count))
1564 {}
1565
1566 bool
1567 operator==(const Operation & other) const noexcept override
1568 {
1569 auto ot = dynamic_cast<const LocalMemoryResponseOperation *>(&other);
1570 // check predicate and value
1571 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1572 }
1573
1574 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1575 CreateOutTypes(const std::shared_ptr<const jlm::llvm::ArrayType> & at, size_t resp_count)
1576 {
1577 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(resp_count, at->GetElementType());
1578 return types;
1579 }
1580
1581 std::string
1582 debug_string() const override
1583 {
1584 return "HLS_LOCAL_MEM_RESP";
1585 }
1586
1587 [[nodiscard]] std::unique_ptr<Operation>
1588 copy() const override
1589 {
1590 return std::make_unique<LocalMemoryResponseOperation>(*this);
1591 }
1592
1593 static std::vector<jlm::rvsdg::Output *>
1594 create(jlm::rvsdg::Output & mem, size_t resp_count)
1595 {
1596 return outputs(&rvsdg::CreateOpNode<LocalMemoryResponseOperation>(
1597 { &mem },
1598 std::dynamic_pointer_cast<const llvm::ArrayType>(mem.Type()),
1599 resp_count));
1600 }
1601};
1602
1604{
1605public:
1606 ~LocalLoadOperation() noexcept override;
1607
1608 LocalLoadOperation(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1609 : SimpleOperation(CreateInTypes(valuetype, numStates), CreateOutTypes(valuetype, numStates))
1610 {}
1611
1612 bool
1613 operator==(const Operation & other) const noexcept override
1614 {
1615 auto ot = dynamic_cast<const LocalLoadOperation *>(&other);
1616 // check predicate and value
1617 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1618 }
1619
1620 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1621 CreateInTypes(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1622 {
1623 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(1, jlm::rvsdg::BitType::Create(64));
1624 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
1625 numStates,
1626 llvm::MemoryStateType::Create());
1627 types.insert(types.end(), states.begin(), states.end());
1628 types.emplace_back(valuetype); // result
1629 return types;
1630 }
1631
1632 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1633 CreateOutTypes(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1634 {
1635 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(1, valuetype);
1636 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
1637 numStates,
1638 llvm::MemoryStateType::Create());
1639 types.insert(types.end(), states.begin(), states.end());
1640 types.emplace_back(jlm::rvsdg::BitType::Create(64)); // addr
1641 return types;
1642 }
1643
1644 std::string
1645 debug_string() const override
1646 {
1647 return "HLS_LOCAL_LOAD_" + argument(narguments() - 1)->debug_string();
1648 }
1649
1650 [[nodiscard]] std::unique_ptr<Operation>
1651 copy() const override
1652 {
1653 return std::make_unique<LocalLoadOperation>(*this);
1654 }
1655
1656 static std::vector<jlm::rvsdg::Output *>
1658 jlm::rvsdg::Output & index,
1659 const std::vector<jlm::rvsdg::Output *> & states,
1660 jlm::rvsdg::Output & load_result)
1661 {
1662 std::vector<jlm::rvsdg::Output *> inputs;
1663 inputs.push_back(&index);
1664 inputs.insert(inputs.end(), states.begin(), states.end());
1665 inputs.push_back(&load_result);
1666 return outputs(
1667 &rvsdg::CreateOpNode<LocalLoadOperation>(inputs, load_result.Type(), states.size()));
1668 }
1669
1670 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
1671 GetLoadedType() const noexcept
1672 {
1673 return result(0);
1674 }
1675};
1676
1678{
1679public:
1680 ~LocalStoreOperation() noexcept override;
1681
1682 LocalStoreOperation(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1683 : SimpleOperation(CreateInTypes(valuetype, numStates), CreateOutTypes(valuetype, numStates))
1684 {}
1685
1686 bool
1687 operator==(const Operation & other) const noexcept override
1688 {
1689 auto ot = dynamic_cast<const LocalStoreOperation *>(&other);
1690 // check predicate and value
1691 return ot && *ot->argument(1) == *argument(1) && ot->narguments() == narguments();
1692 }
1693
1694 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1695 CreateInTypes(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1696 {
1697 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(
1698 { jlm::rvsdg::BitType::Create(64), valuetype });
1699 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> states(
1700 numStates,
1701 llvm::MemoryStateType::Create());
1702 types.insert(types.end(), states.begin(), states.end());
1703 return types;
1704 }
1705
1706 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1707 CreateOutTypes(const std::shared_ptr<const jlm::rvsdg::Type> & valuetype, size_t numStates)
1708 {
1709 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(
1710 numStates,
1711 llvm::MemoryStateType::Create());
1712 types.emplace_back(jlm::rvsdg::BitType::Create(64)); // addr
1713 types.emplace_back(valuetype); // data
1714 return types;
1715 }
1716
1717 std::string
1718 debug_string() const override
1719 {
1720 return "HLS_LOCAL_STORE_" + argument(narguments() - 1)->debug_string();
1721 }
1722
1723 [[nodiscard]] std::unique_ptr<Operation>
1724 copy() const override
1725 {
1726 return std::make_unique<LocalStoreOperation>(*this);
1727 }
1728
1729 static std::vector<jlm::rvsdg::Output *>
1731 jlm::rvsdg::Output & index,
1732 jlm::rvsdg::Output & value,
1733 const std::vector<jlm::rvsdg::Output *> & states)
1734 {
1735 std::vector<jlm::rvsdg::Output *> inputs;
1736 inputs.push_back(&index);
1737 inputs.push_back(&value);
1738 inputs.insert(inputs.end(), states.begin(), states.end());
1739 return outputs(&rvsdg::CreateOpNode<LocalStoreOperation>(inputs, value.Type(), states.size()));
1740 }
1741
1742 [[nodiscard]] const jlm::rvsdg::Type &
1743 GetStoredType() const noexcept
1744 {
1745 return *argument(1).get();
1746 }
1747};
1748
1750{
1751public:
1752 ~LocalMemoryRequestOperation() noexcept override;
1753
1755 const std::shared_ptr<const llvm::ArrayType> & at,
1756 size_t load_cnt,
1757 size_t store_cnt)
1758 : SimpleOperation(CreateInTypes(at, load_cnt, store_cnt), {})
1759 {}
1760
1761 bool
1762 operator==(const Operation & other) const noexcept override
1763 {
1764 auto ot = dynamic_cast<const LocalMemoryRequestOperation *>(&other);
1765 // check predicate and value
1766 return ot && ot->narguments() == narguments()
1767 && (ot->narguments() == 0 || (*ot->argument(1) == *argument(1)))
1768 && ot->narguments() == narguments();
1769 }
1770
1771 static std::vector<std::shared_ptr<const jlm::rvsdg::Type>>
1773 const std::shared_ptr<const llvm::ArrayType> & at,
1774 size_t load_cnt,
1775 size_t store_cnt)
1776 {
1777 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types(1, at);
1778 for (size_t i = 0; i < load_cnt; ++i)
1779 {
1780 types.emplace_back(jlm::rvsdg::BitType::Create(64)); // addr
1781 }
1782 for (size_t i = 0; i < store_cnt; ++i)
1783 {
1784 types.emplace_back(jlm::rvsdg::BitType::Create(64)); // addr
1785 types.emplace_back(at->GetElementType()); // data
1786 }
1787 return types;
1788 }
1789
1790 std::string
1791 debug_string() const override
1792 {
1793 return "HLS_LOCAL_MEM_REQ";
1794 }
1795
1796 [[nodiscard]] std::unique_ptr<Operation>
1797 copy() const override
1798 {
1799 return std::make_unique<LocalMemoryRequestOperation>(*this);
1800 }
1801
1802 static std::vector<jlm::rvsdg::Output *>
1804 jlm::rvsdg::Output & mem,
1805 const std::vector<jlm::rvsdg::Output *> & load_operands,
1806 const std::vector<jlm::rvsdg::Output *> & store_operands)
1807 {
1808 JLM_ASSERT(store_operands.size() % 2 == 0);
1809 std::vector operands(1, &mem);
1810 operands.insert(operands.end(), load_operands.begin(), load_operands.end());
1811 operands.insert(operands.end(), store_operands.begin(), store_operands.end());
1812 return outputs(&rvsdg::CreateOpNode<LocalMemoryRequestOperation>(
1813 operands,
1814 std::dynamic_pointer_cast<const llvm::ArrayType>(mem.Type()),
1815 load_operands.size(),
1816 store_operands.size() / 2));
1817 }
1818};
1819
1820}
1821#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:1058
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(std::shared_ptr< const llvm::PointerType > pointerType)
Definition hls.hpp:1075
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1091
~AddressQueueOperation() noexcept override
std::string debug_string() const override
Definition hls.hpp:1081
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:1097
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(std::shared_ptr< const llvm::PointerType > pointerType)
Definition hls.hpp:1066
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:944
BundleType(const BundleType &)=default
const std::vector< std::pair< std::string, std::shared_ptr< const jlm::rvsdg::Type > > > elements_
Definition hls.hpp:951
~BundleType() noexcept override
BundleType & operator=(const BundleType &)=delete
BundleType(BundleType &&)=delete
bool operator==(const jlm::rvsdg::Type &other) const noexcept override
Definition hls.hpp:904
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(std::shared_ptr< const rvsdg::Type > pointeeType)
Definition hls.hpp:1185
~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:1218
std::string debug_string() const override
Definition hls.hpp:1205
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1177
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1212
std::shared_ptr< const rvsdg::Type > GetLoadedType() const noexcept
Definition hls.hpp:1235
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(std::shared_ptr< const rvsdg::Type > pointeeType)
Definition hls.hpp:1195
const llvm::PointerType & GetPointerType() const noexcept
Definition hls.hpp:1229
~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:1037
const llvm::PointerType & GetPointerType() const noexcept
Definition hls.hpp:1031
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:972
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(std::shared_ptr< const rvsdg::Type > pointeeType, size_t numStates)
Definition hls.hpp:994
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1012
~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:980
std::string debug_string() const override
Definition hls.hpp:1006
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:1018
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1613
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:1657
std::shared_ptr< const rvsdg::Type > GetLoadedType() const noexcept
Definition hls.hpp:1671
std::string debug_string() const override
Definition hls.hpp:1645
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:1633
~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:1621
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1651
bool operator==(const Operation &) const noexcept override
Definition hls.hpp:1526
static std::vector< jlm::rvsdg::Output * > create(std::shared_ptr< const llvm::ArrayType > at, rvsdg::Region *region)
Definition hls.hpp:1551
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1545
std::string debug_string() const override
Definition hls.hpp:1539
~LocalMemoryOperation() noexcept override
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateOutTypes(std::shared_ptr< const llvm::ArrayType > at)
Definition hls.hpp:1532
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1797
~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:1803
std::string debug_string() const override
Definition hls.hpp:1791
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1762
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:1772
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1567
~LocalMemoryResponseOperation() noexcept override
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1588
std::string debug_string() const override
Definition hls.hpp:1582
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &mem, size_t resp_count)
Definition hls.hpp:1594
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:1575
~LocalStoreOperation() noexcept override
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1724
std::string debug_string() const override
Definition hls.hpp:1718
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:1730
const jlm::rvsdg::Type & GetStoredType() const noexcept
Definition hls.hpp:1743
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1687
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:1695
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:1707
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:806
rvsdg::Output & GetPredicateBuffer() const noexcept
Definition hls.hpp:814
~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:1418
const std::vector< std::shared_ptr< const rvsdg::Type > > * GetStoreTypes() const
Definition hls.hpp:1424
~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:1340
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:1392
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:1358
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1330
MemoryRequestOperation(const MemoryRequestOperation &other)=default
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1386
std::vector< std::shared_ptr< const rvsdg::Type > > LoadTypes_
Definition hls.hpp:1430
std::string debug_string() const override
Definition hls.hpp:1380
std::vector< std::shared_ptr< const rvsdg::Type > > StoreTypes_
Definition hls.hpp:1431
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1289
static std::vector< std::shared_ptr< const jlm::rvsdg::Type > > CreateInTypes(int in_width)
Definition hls.hpp:1263
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:1271
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:1295
std::string debug_string() const override
Definition hls.hpp:1283
~MemoryResponseOperation() noexcept override
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1255
~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:1126
~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:1134
static std::vector< jlm::rvsdg::Output * > create(jlm::rvsdg::Output &addr, const std::vector< jlm::rvsdg::Output * > &states)
Definition hls.hpp:1157
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1151
std::string debug_string() const override
Definition hls.hpp:1145
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:1466
~StoreOperation() noexcept override
std::unique_ptr< Operation > copy() const override
Definition hls.hpp:1483
bool operator==(const Operation &other) const noexcept override
Definition hls.hpp:1446
const rvsdg::Type & GetStoredType() const noexcept
Definition hls.hpp:1510
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:1454
std::string debug_string() const override
Definition hls.hpp:1477
const llvm::PointerType & GetPointerType() const noexcept
Definition hls.hpp:1504
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:1489
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:61
rvsdg::TypeKind Kind() const noexcept override
Return the kind of this type.
Definition hls.cpp:67
static std::shared_ptr< const TriggerType > Create()
Definition hls.cpp:73
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:448
std::shared_ptr< const BundleType > get_mem_req_type(std::shared_ptr< const rvsdg::Type > elementType, bool write)
Definition hls.cpp:433
int JlmSize(const jlm::rvsdg::Type *type)
Definition hls.cpp:457
size_t GetPointerSizeInBits()
Definition hls.cpp:509
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
Variable passed between hls loop iterations.
Definition hls.hpp:752
rvsdg::Output * pre
Variable at beginning of loop (pre-iteration value).
Definition hls.hpp:756
rvsdg::Input * post
Variable at end of loop (post-iteration value).
Definition hls.hpp:760
Variable entering the hls loop.
Definition hls.hpp:722
rvsdg::Output * inner
Variable in region representing entry value.
Definition hls.hpp:730
rvsdg::Input * input
Variable at loop entry.
Definition hls.hpp:726
Variable exiting the hls loop.
Definition hls.hpp:737
rvsdg::Output * output
Variable after loop exit.
Definition hls.hpp:745
rvsdg::Input * inner
Variable in region representing exit value.
Definition hls.hpp:741