Jlm
Loading...
Searching...
No Matches
operators.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2014 2015 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#ifndef JLM_LLVM_IR_OPERATORS_OPERATORS_HPP
7#define JLM_LLVM_IR_OPERATORS_OPERATORS_HPP
8
11#include <jlm/llvm/ir/tac.hpp>
12#include <jlm/llvm/ir/types.hpp>
13#include <jlm/rvsdg/binary.hpp>
15#include <jlm/rvsdg/control.hpp>
17#include <jlm/rvsdg/type.hpp>
18#include <jlm/rvsdg/unary.hpp>
19
20#include <llvm/ADT/APFloat.h>
21#include <llvm/IR/InstrTypes.h>
22#include <stdexcept>
23
24namespace jlm::llvm
25{
26
35{
36public:
37 ~SsaPhiOperation() noexcept override;
38
40 std::vector<ControlFlowGraphNode *> incomingNodes,
41 const std::shared_ptr<const jlm::rvsdg::Type> & type)
42 : SimpleOperation({ incomingNodes.size(), type }, { type }),
43 IncomingNodes_(std::move(incomingNodes))
44 {}
45
46 SsaPhiOperation(const SsaPhiOperation &) = default;
47
49 operator=(const SsaPhiOperation &) = delete;
50
53
54 bool
55 operator==(const Operation & other) const noexcept override;
56
57 std::string
58 debug_string() const override;
59
60 [[nodiscard]] std::unique_ptr<Operation>
61 copy() const override;
62
63 const std::shared_ptr<const rvsdg::Type> &
64 Type() const noexcept
65 {
66 return result(0);
67 }
68
70 GetIncomingNode(size_t n) const noexcept
71 {
73 return IncomingNodes_[n];
74 }
75
76 static std::unique_ptr<llvm::ThreeAddressCode>
78 const std::vector<std::pair<const Variable *, ControlFlowGraphNode *>> & arguments,
79 std::shared_ptr<const jlm::rvsdg::Type> type)
80 {
81 std::vector<ControlFlowGraphNode *> basicBlocks;
82 std::vector<const Variable *> operands;
83 for (const auto & argument : arguments)
84 {
85 basicBlocks.push_back(argument.second);
86 operands.push_back(argument.first);
87 }
88
89 auto phi = std::make_unique<SsaPhiOperation>(std::move(basicBlocks), std::move(type));
90 return ThreeAddressCode::create(std::move(phi), operands);
91 }
92
93private:
94 std::vector<ControlFlowGraphNode *> IncomingNodes_;
95};
96
98{
99public:
100 ~AssignmentOperation() noexcept override;
101
102 explicit AssignmentOperation(const std::shared_ptr<const rvsdg::Type> & type)
103 : SimpleOperation({ type, type }, {})
104 {}
105
107
109
110 bool
111 operator==(const Operation & other) const noexcept override;
112
113 [[nodiscard]] std::string
114 debug_string() const override;
115
116 [[nodiscard]] std::unique_ptr<Operation>
117 copy() const override;
118
119 static std::unique_ptr<llvm::ThreeAddressCode>
120 create(const Variable * rhs, const Variable * lhs)
121 {
122 if (rhs->type() != lhs->type())
123 throw util::Error("LHS and RHS of assignment must have same type.");
124
125 auto operation = std::make_unique<AssignmentOperation>(rhs->Type());
126 return ThreeAddressCode::create(std::move(operation), { lhs, rhs });
127 }
128};
129
131{
132public:
133 ~SelectOperation() noexcept override;
134
135 explicit SelectOperation(const std::shared_ptr<const rvsdg::Type> & type)
137 {}
138
139 bool
140 operator==(const Operation & other) const noexcept override;
141
142 std::string
143 debug_string() const override;
144
145 [[nodiscard]] std::unique_ptr<Operation>
146 copy() const override;
147
148 [[nodiscard]] const jlm::rvsdg::Type &
149 type() const noexcept
150 {
151 return *result(0);
152 }
153
154 [[nodiscard]] const std::shared_ptr<const jlm::rvsdg::Type> &
155 Type() const noexcept
156 {
157 return result(0);
158 }
159
160 static std::unique_ptr<llvm::ThreeAddressCode>
161 create(const llvm::Variable * p, const llvm::Variable * t, const llvm::Variable * f)
162 {
163 auto op = std::make_unique<SelectOperation>(t->Type());
164 return ThreeAddressCode::create(std::move(op), { p, t, f });
165 }
166};
167
169{
170public:
171 ~VectorSelectOperation() noexcept override;
172
173private:
175 const std::shared_ptr<const VectorType> & pt,
176 const std::shared_ptr<const VectorType> & vt)
177 : SimpleOperation({ pt, vt, vt }, { vt })
178 {}
179
180public:
181 bool
182 operator==(const Operation & other) const noexcept override;
183
184 [[nodiscard]] std::string
185 debug_string() const override;
186
187 [[nodiscard]] std::unique_ptr<Operation>
188 copy() const override;
189
190 [[nodiscard]] const rvsdg::Type &
191 type() const noexcept
192 {
193 return *result(0);
194 }
195
196 [[nodiscard]] const std::shared_ptr<const rvsdg::Type> &
197 Type() const noexcept
198 {
199 return result(0);
200 }
201
202 size_t
203 size() const noexcept
204 {
205 return dynamic_cast<const VectorType *>(&type())->size();
206 }
207
208 static std::unique_ptr<llvm::ThreeAddressCode>
209 create(const Variable * p, const Variable * t, const Variable * f)
210 {
211 if (is<FixedVectorType>(p->type()) && is<FixedVectorType>(t->type()))
212 return createVectorSelectTac<FixedVectorType>(p, t, f);
213
214 if (is<ScalableVectorType>(p->type()) && is<ScalableVectorType>(t->type()))
215 return createVectorSelectTac<ScalableVectorType>(p, t, f);
216
217 throw util::Error("Expected vector types as operands.");
218 }
219
220private:
221 template<typename T>
222 static std::unique_ptr<ThreeAddressCode>
223 createVectorSelectTac(const Variable * p, const Variable * t, const Variable * f)
224 {
225 auto fvt = static_cast<const T *>(&t->type());
226 auto pt = T::Create(jlm::rvsdg::BitType::Create(1), fvt->size());
227 auto vt = T::Create(fvt->Type(), fvt->size());
228 auto op = std::unique_ptr<VectorSelectOperation>(new VectorSelectOperation(pt, vt));
229 return ThreeAddressCode::create(std::move(op), { p, t, f });
230 }
231};
232
234{
235public:
236 ~BranchOperation() noexcept override;
237
238 explicit BranchOperation(std::shared_ptr<const rvsdg::ControlType> type)
239 : SimpleOperation({ std::move(type) }, {})
240 {}
241
242 bool
243 operator==(const Operation & other) const noexcept override;
244
245 [[nodiscard]] std::string
246 debug_string() const override;
247
248 [[nodiscard]] std::unique_ptr<Operation>
249 copy() const override;
250
251 inline size_t
252 nalternatives() const noexcept
253 {
254 return std::static_pointer_cast<const rvsdg::ControlType>(argument(0))->nalternatives();
255 }
256
257 static std::unique_ptr<llvm::ThreeAddressCode>
258 create(size_t nalternatives, const Variable * operand)
259 {
260 auto op = std::make_unique<BranchOperation>(rvsdg::ControlType::Create(nalternatives));
261 return ThreeAddressCode::create(std::move(op), { operand });
262 }
263};
264
270{
271public:
272 ~ConstantPointerNullOperation() noexcept override;
273
277
278 bool
279 operator==(const Operation & other) const noexcept override;
280
281 [[nodiscard]] std::string
282 debug_string() const override;
283
284 [[nodiscard]] std::unique_ptr<Operation>
285 copy() const override;
286
287 static std::unique_ptr<ThreeAddressCode>
289 {
290 return ThreeAddressCode::create(std::make_unique<ConstantPointerNullOperation>(), {});
291 }
292
293 static rvsdg::Node &
298};
299
304{
305public:
306 ~ConstantDataArrayOperation() noexcept override;
307
308 ConstantDataArrayOperation(const std::shared_ptr<const rvsdg::Type> & type, size_t size)
310 {
311 if (size == 0)
312 throw util::Error("size equals zero.");
313 }
314
315 bool
316 operator==(const Operation & other) const noexcept override;
317
318 [[nodiscard]] std::string
319 debug_string() const override;
320
321 [[nodiscard]] std::unique_ptr<Operation>
322 copy() const override;
323
324 size_t
325 size() const noexcept
326 {
327 return std::static_pointer_cast<const ArrayType>(result(0))->nelements();
328 }
329
330 [[nodiscard]] std::shared_ptr<const ArrayType>
331 type() const noexcept
332 {
333 JLM_ASSERT(std::dynamic_pointer_cast<const ArrayType>(result(0)));
334 return std::static_pointer_cast<const ArrayType>(result(0));
335 }
336
337 static std::unique_ptr<ThreeAddressCode>
338 create(const std::vector<const Variable *> & elements)
339 {
340 if (elements.size() == 0)
341 throw util::Error("expected at least one element.");
342
343 auto vt = elements[0]->Type();
344 if (vt->Kind() != rvsdg::TypeKind::Value)
345 throw util::Error("expected value type.");
346
347 auto op = std::make_unique<ConstantDataArrayOperation>(std::move(vt), elements.size());
348 return ThreeAddressCode::create(std::move(op), elements);
349 }
350
351 static rvsdg::Output *
352 Create(const std::vector<rvsdg::Output *> & elements)
353 {
354 if (elements.empty())
355 throw util::Error("Expected at least one element.");
356
357 auto valueType = elements[0]->Type();
358 if (valueType->Kind() != rvsdg::TypeKind::Value)
359 {
360 throw util::Error("Expected value type.");
361 }
362
364 elements,
365 std::move(valueType),
366 elements.size())
367 .output(0);
368 }
369};
370
376{
377 Eq,
378 Ne,
379 Ugt,
380 Uge,
381 Ult,
382 Ule,
383 Sgt,
384 Sge,
385 Slt,
386 Sle
387};
388
393[[nodiscard]] ICmpPredicate
394convertICmpPredicateToJlm(::llvm::CmpInst::Predicate predicate);
395
400[[nodiscard]] ::llvm::CmpInst::Predicate
402
407[[nodiscard]] std::string_view
409
411{
412public:
413 ~PtrCmpOperation() noexcept override;
414
415 PtrCmpOperation(const std::shared_ptr<const PointerType> & ptype, ICmpPredicate predicate)
416 : BinaryOperation({ ptype, ptype }, jlm::rvsdg::BitType::Create(1)),
418 {}
419
420 bool
421 operator==(const Operation & other) const noexcept override;
422
423 [[nodiscard]] std::string
424 debug_string() const override;
425
426 [[nodiscard]] std::unique_ptr<Operation>
427 copy() const override;
428
431 const noexcept override;
432
436 jlm::rvsdg::Output * op1,
437 jlm::rvsdg::Output * op2) const override;
438
440 predicate() const noexcept
441 {
442 return predicate_;
443 }
444
445 static std::unique_ptr<llvm::ThreeAddressCode>
446 create(ICmpPredicate predicateKind, const Variable * op1, const Variable * op2)
447 {
448 auto pt = std::dynamic_pointer_cast<const PointerType>(op1->Type());
449 if (!pt)
450 throw util::Error("expected pointer type.");
451
452 auto op = std::make_unique<PtrCmpOperation>(std::move(pt), predicateKind);
453 return ThreeAddressCode::create(std::move(op), { op1, op2 });
454 }
455
456 static rvsdg::SimpleNode &
457 createNode(const ICmpPredicate kind, rvsdg::Output & operand1, rvsdg::Output & operand2)
458 {
460 { &operand1, &operand2 },
462 kind);
463 }
464
478 static std::optional<std::vector<rvsdg::Output *>>
480 const PtrCmpOperation & ptrCmpOperation,
481 const std::vector<rvsdg::Output *> & operands);
482
499 static std::optional<std::vector<rvsdg::Output *>>
501 const PtrCmpOperation & ptrCmpOperation,
502 const std::vector<rvsdg::Output *> & operands);
503
504private:
506};
507
508/* floating point constant operator */
509
511{
512public:
513 ~ConstantFP() noexcept override;
514
515 inline ConstantFP(const fpsize & size, const ::llvm::APFloat & constant)
518 {}
519
520 ConstantFP(std::shared_ptr<const FloatingPointType> fpt, const ::llvm::APFloat & constant)
521 : SimpleOperation({}, { std::move(fpt) }),
523 {}
524
525 bool
526 operator==(const Operation & other) const noexcept override;
527
528 [[nodiscard]] std::string
529 debug_string() const override;
530
531 [[nodiscard]] std::unique_ptr<Operation>
532 copy() const override;
533
534 inline const ::llvm::APFloat &
535 constant() const noexcept
536 {
537 return constant_;
538 }
539
540 inline const fpsize &
541 size() const noexcept
542 {
543 return std::static_pointer_cast<const FloatingPointType>(result(0))->size();
544 }
545
546 [[nodiscard]] static std::unique_ptr<ConstantFP>
547 create(const ::llvm::APFloat & constant, const std::shared_ptr<const jlm::rvsdg::Type> & type)
548 {
549 auto ft = std::dynamic_pointer_cast<const FloatingPointType>(type);
550 if (!ft)
551 throw util::Error("expected floating point type.");
552
553 return std::make_unique<ConstantFP>(std::move(ft), constant);
554 }
555
556 [[nodiscard]] static std::unique_ptr<llvm::ThreeAddressCode>
557 createTac(const ::llvm::APFloat & constant, const std::shared_ptr<const jlm::rvsdg::Type> & type)
558 {
559 return ThreeAddressCode::create(create(constant, type), {});
560 }
561
562 [[nodiscard]] static rvsdg::Node &
563 createNode(rvsdg::Region & region, fpsize size, const ::llvm::APFloat & constant)
564 {
566 }
567
571 [[nodiscard]] static ::llvm::APFloat
573 {
574 switch (size)
575 {
576 case fpsize::half:
577 return ::llvm::APFloat::getZero(::llvm::APFloat::IEEEhalf());
578 case fpsize::flt:
579 return ::llvm::APFloat::getZero(::llvm::APFloat::IEEEsingle());
580 case fpsize::dbl:
581 return ::llvm::APFloat::getZero(::llvm::APFloat::IEEEdouble());
582 case fpsize::x86fp80:
583 return ::llvm::APFloat::getZero(::llvm::APFloat::x87DoubleExtended());
584 case fpsize::fp128:
585 return ::llvm::APFloat::getZero(::llvm::APFloat::IEEEquad());
586 default:
587 JLM_UNREACHABLE("Unknown float size");
588 }
589 }
590
591private:
592 /* FIXME: I would not like to use the APFloat here,
593 but I don't have a replacement right now. */
594 ::llvm::APFloat constant_;
595};
596
597/* floating point comparison operator */
598
599enum class fpcmp
600{
601 TRUE,
602 FALSE,
603 oeq,
604 ogt,
605 oge,
606 olt,
607 ole,
608 one,
609 ord,
610 ueq,
611 ugt,
612 uge,
613 ult,
614 ule,
615 une,
616 uno
617};
618
620{
621public:
622 ~FCmpOperation() noexcept override;
623
630
631 FCmpOperation(const fpcmp & cmp, const std::shared_ptr<const FloatingPointType> & fpt)
633 cmp_(cmp)
634 {}
635
636 bool
637 operator==(const Operation & other) const noexcept override;
638
639 [[nodiscard]] std::string
640 debug_string() const override;
641
642 [[nodiscard]] std::unique_ptr<Operation>
643 copy() const override;
644
647 const noexcept override;
648
652 jlm::rvsdg::Output * op1,
653 jlm::rvsdg::Output * op2) const override;
654
655 inline const fpcmp &
656 cmp() const noexcept
657 {
658 return cmp_;
659 }
660
661 inline const fpsize &
662 size() const noexcept
663 {
664 return std::static_pointer_cast<const FloatingPointType>(argument(0))->size();
665 }
666
677 static std::optional<std::vector<rvsdg::Output *>>
678 foldConstants(const FCmpOperation & operation, const std::vector<rvsdg::Output *> & operands);
679
680 static std::unique_ptr<llvm::ThreeAddressCode>
681 create(const fpcmp & cmp, const Variable * op1, const Variable * op2)
682 {
683 auto ft = std::dynamic_pointer_cast<const FloatingPointType>(op1->Type());
684 if (!ft)
685 throw util::Error("expected floating point type.");
686
687 auto op = std::make_unique<FCmpOperation>(cmp, std::move(ft));
688 return ThreeAddressCode::create(std::move(op), { op1, op2 });
689 }
690
691private:
693};
694
700{
701public:
702 ~UndefValueOperation() noexcept override;
703
704 explicit UndefValueOperation(std::shared_ptr<const jlm::rvsdg::Type> type)
705 : SimpleOperation({}, { std::move(type) })
706 {}
707
709
712
715
716 bool
717 operator==(const Operation & other) const noexcept override;
718
719 [[nodiscard]] std::string
720 debug_string() const override;
721
722 [[nodiscard]] std::unique_ptr<Operation>
723 copy() const override;
724
725 [[nodiscard]] const rvsdg::Type &
726 GetType() const noexcept
727 {
728 return *result(0);
729 }
730
731 static jlm::rvsdg::Output *
732 Create(rvsdg::Region & region, std::shared_ptr<const jlm::rvsdg::Type> type)
733 {
734 return rvsdg::CreateOpNode<UndefValueOperation>(region, std::move(type)).output(0);
735 }
736
737 static std::unique_ptr<llvm::ThreeAddressCode>
738 Create(std::shared_ptr<const jlm::rvsdg::Type> type)
739 {
740 auto operation = std::make_unique<UndefValueOperation>(std::move(type));
741 return ThreeAddressCode::create(std::move(operation), {});
742 }
743
744 static std::unique_ptr<llvm::ThreeAddressCode>
745 Create(std::shared_ptr<const jlm::rvsdg::Type> type, const std::string & name)
746 {
747 auto operation = std::make_unique<UndefValueOperation>(std::move(type));
748 return ThreeAddressCode::create(std::move(operation), {}, { name });
749 }
750
751 static std::unique_ptr<llvm::ThreeAddressCode>
752 Create(std::unique_ptr<ThreeAddressCodeVariable> result)
753 {
754 auto & type = result->Type();
755
756 std::vector<std::unique_ptr<ThreeAddressCodeVariable>> results;
757 results.push_back(std::move(result));
758
759 auto operation = std::make_unique<UndefValueOperation>(type);
760 return ThreeAddressCode::create(std::move(operation), {}, std::move(results));
761 }
762};
763
769{
770public:
771 ~PoisonValueOperation() noexcept override;
772
773 explicit PoisonValueOperation(std::shared_ptr<const jlm::rvsdg::Type> type)
774 : SimpleOperation({}, { std::move(type) })
775 {}
776
778
780
783
786
787 bool
788 operator==(const Operation & other) const noexcept override;
789
790 std::string
791 debug_string() const override;
792
793 [[nodiscard]] std::unique_ptr<Operation>
794 copy() const override;
795
796 const jlm::rvsdg::Type &
797 GetType() const noexcept
798 {
799 return *result(0).get();
800 }
801
802 static std::unique_ptr<llvm::ThreeAddressCode>
803 Create(const std::shared_ptr<const jlm::rvsdg::Type> & type)
804 {
805 auto valueType = CheckAndConvertType(type);
806
807 auto operation = std::make_unique<PoisonValueOperation>(std::move(valueType));
808 return ThreeAddressCode::create(std::move(operation), {});
809 }
810
811 static jlm::rvsdg::Output *
812 Create(rvsdg::Region * region, const std::shared_ptr<const jlm::rvsdg::Type> & type)
813 {
814 auto valueType = CheckAndConvertType(type);
815
816 return rvsdg::CreateOpNode<PoisonValueOperation>(*region, std::move(valueType)).output(0);
817 }
818
819private:
820 static std::shared_ptr<const jlm::rvsdg::Type>
821 CheckAndConvertType(const std::shared_ptr<const jlm::rvsdg::Type> & type)
822 {
823 if (type->Kind() == rvsdg::TypeKind::Value)
824 return type;
825
826 throw util::Error("Expected value type.");
827 }
828};
829
837{
838public:
839 ~FreezeOperation() noexcept override;
840
841 explicit FreezeOperation(std::shared_ptr<const jlm::rvsdg::Type> type)
842 : rvsdg::UnaryOperation(type, type)
843 {
844 if (type->Kind() != rvsdg::TypeKind::Value)
845 throw std::runtime_error("FreezeOperation given non-value type");
846 }
847
848 bool
849 operator==(const Operation & other) const noexcept override;
850
851 std::string
852 debug_string() const override;
853
854 [[nodiscard]] std::unique_ptr<Operation>
855 copy() const override;
856
857 const jlm::rvsdg::Type &
858 getType() const noexcept
859 {
860 return *result(0).get();
861 }
862
863 static std::unique_ptr<llvm::ThreeAddressCode>
864 createTac(const Variable & operand)
865 {
866 auto operation = std::make_unique<FreezeOperation>(operand.Type());
867 return ThreeAddressCode::create(std::move(operation), { &operand });
868 }
869
870 static jlm::rvsdg::Node &
872 {
873 return rvsdg::CreateOpNode<FreezeOperation>({ &operand }, operand.Type());
874 }
875};
876
877/* floating point arithmetic operator */
878
879enum class fpop
880{
881 add,
882 sub,
883 mul,
884 div,
885 mod
886};
887
889{
890public:
891 ~FBinaryOperation() noexcept override;
892
899
900 FBinaryOperation(const llvm::fpop & op, const std::shared_ptr<const FloatingPointType> & fpt)
901 : BinaryOperation({ fpt, fpt }, fpt),
902 op_(op)
903 {}
904
905 bool
906 operator==(const Operation & other) const noexcept override;
907
908 [[nodiscard]] std::string
909 debug_string() const override;
910
911 [[nodiscard]] std::unique_ptr<Operation>
912 copy() const override;
913
916 const noexcept override;
917
921 jlm::rvsdg::Output * op1,
922 jlm::rvsdg::Output * op2) const override;
923
924 inline const llvm::fpop &
925 fpop() const noexcept
926 {
927 return op_;
928 }
929
930 inline const fpsize &
931 size() const noexcept
932 {
933 return std::static_pointer_cast<const FloatingPointType>(result(0))->size();
934 }
935
936 static std::unique_ptr<llvm::ThreeAddressCode>
937 create(const llvm::fpop & fpop, const Variable * op1, const Variable * op2)
938 {
939 auto ft = std::dynamic_pointer_cast<const FloatingPointType>(op1->Type());
940 if (!ft)
941 throw util::Error("expected floating point type.");
942
943 auto op = std::make_unique<FBinaryOperation>(fpop, ft);
944 return ThreeAddressCode::create(std::move(op), { op1, op2 });
945 }
946
957 static std::optional<std::vector<rvsdg::Output *>>
958 foldConstants(const FBinaryOperation & operation, const std::vector<rvsdg::Output *> & operands);
959
960private:
962};
963
965{
966public:
967 ~FNegOperation() noexcept override;
968
969 explicit FNegOperation(const fpsize & size)
971 {}
972
973 explicit FNegOperation(const std::shared_ptr<const FloatingPointType> & fpt)
974 : UnaryOperation(fpt, fpt)
975 {}
976
977 bool
978 operator==(const Operation & other) const noexcept override;
979
980 [[nodiscard]] std::string
981 debug_string() const override;
982
983 [[nodiscard]] std::unique_ptr<Operation>
984 copy() const override;
985
986 const fpsize &
987 size() const noexcept
988 {
989 return std::static_pointer_cast<const FloatingPointType>(argument(0))->size();
990 }
991
992 static std::unique_ptr<llvm::ThreeAddressCode>
993 create(const Variable * operand)
994 {
995 auto type = std::dynamic_pointer_cast<const FloatingPointType>(operand->Type());
996 if (!type)
997 throw util::Error("expected floating point type.");
998
999 auto op = std::make_unique<FNegOperation>(std::move(type));
1000 return ThreeAddressCode::create(std::move(op), { operand });
1001 }
1002};
1003
1005{
1006public:
1008
1009 explicit VariadicArgumentListOperation(std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types)
1010 : SimpleOperation(std::move(types), { VariableArgumentType::Create() })
1011 {}
1012
1014
1017
1020
1021 bool
1022 operator==(const Operation & other) const noexcept override;
1023
1024 [[nodiscard]] std::string
1025 debug_string() const override;
1026
1027 [[nodiscard]] std::unique_ptr<Operation>
1028 copy() const override;
1029
1030 static std::unique_ptr<llvm::ThreeAddressCode>
1031 create(const std::vector<const Variable *> & arguments)
1032 {
1033 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> operands;
1034 for (const auto & argument : arguments)
1035 operands.push_back(argument->Type());
1036
1037 auto op = std::make_unique<VariadicArgumentListOperation>(std::move(operands));
1038 return ThreeAddressCode::create(std::move(op), arguments);
1039 }
1040
1041 static rvsdg::Output *
1042 Create(rvsdg::Region & region, const std::vector<rvsdg::Output *> & operands)
1043 {
1044 std::vector<std::shared_ptr<const rvsdg::Type>> operandTypes;
1045 operandTypes.reserve(operands.size());
1046 for (auto & operand : operands)
1047 operandTypes.emplace_back(operand->Type());
1048
1049 return operands.empty()
1050 ? rvsdg::CreateOpNode<VariadicArgumentListOperation>(region, std::move(operandTypes))
1051 .output(0)
1052 : rvsdg::CreateOpNode<VariadicArgumentListOperation>(operands, std::move(operandTypes))
1053 .output(0);
1054 }
1055};
1056
1058{
1059public:
1060 ~ConstantStructOperation() noexcept override;
1061
1062 explicit ConstantStructOperation(std::shared_ptr<const StructType> type)
1064 {}
1065
1066 bool
1067 operator==(const Operation & other) const noexcept override;
1068
1069 [[nodiscard]] std::string
1070 debug_string() const override;
1071
1072 [[nodiscard]] std::unique_ptr<Operation>
1073 copy() const override;
1074
1075 const StructType &
1076 type() const noexcept
1077 {
1078 return *std::static_pointer_cast<const StructType>(result(0));
1079 }
1080
1081 static std::unique_ptr<ThreeAddressCode>
1083 const std::vector<const Variable *> & elements,
1084 const std::shared_ptr<const rvsdg::Type> & type)
1085 {
1086 auto structType = CheckAndExtractStructType(type);
1087
1088 auto op = std::make_unique<ConstantStructOperation>(std::move(structType));
1089 return ThreeAddressCode::create(std::move(op), elements);
1090 }
1091
1092 static rvsdg::Output &
1094 rvsdg::Region &,
1095 const std::vector<rvsdg::Output *> & operands,
1096 std::shared_ptr<const rvsdg::Type> resultType)
1097 {
1098 auto structType = CheckAndExtractStructType(std::move(resultType));
1099 return *rvsdg::CreateOpNode<ConstantStructOperation>(operands, std::move(structType)).output(0);
1100 }
1101
1102private:
1103 static std::vector<std::shared_ptr<const rvsdg::Type>>
1105 {
1106 std::vector<std::shared_ptr<const rvsdg::Type>> types;
1107 for (size_t n = 0; n < type.numElements(); n++)
1108 types.push_back(type.getElementType(n));
1109
1110 return types;
1111 }
1112
1113 static std::shared_ptr<const StructType>
1114 CheckAndExtractStructType(std::shared_ptr<const rvsdg::Type> type)
1115 {
1116 if (auto structType = std::dynamic_pointer_cast<const StructType>(type))
1117 {
1118 return structType;
1119 }
1120
1121 throw util::TypeError("StructType", type->debug_string());
1122 }
1123};
1124
1126{
1127public:
1128 ~ConstantArrayOperation() noexcept override;
1129
1130 ConstantArrayOperation(const std::shared_ptr<const jlm::rvsdg::Type> & type, size_t size)
1132 {
1133 if (size == 0)
1134 throw util::Error("size equals zero.\n");
1135 }
1136
1137 bool
1138 operator==(const Operation & other) const noexcept override;
1139
1140 [[nodiscard]] std::string
1141 debug_string() const override;
1142
1143 [[nodiscard]] std::unique_ptr<Operation>
1144 copy() const override;
1145
1146 size_t
1147 size() const noexcept
1148 {
1149 return std::static_pointer_cast<const ArrayType>(result(0))->nelements();
1150 }
1151
1152 [[nodiscard]] std::shared_ptr<const ArrayType>
1153 type() const noexcept
1154 {
1155 JLM_ASSERT(std::dynamic_pointer_cast<const ArrayType>(result(0)));
1156 return std::static_pointer_cast<const ArrayType>(result(0));
1157 }
1158
1159 static std::unique_ptr<llvm::ThreeAddressCode>
1160 create(const std::vector<const Variable *> & elements)
1161 {
1162 if (elements.size() == 0)
1163 throw util::Error("expected at least one element.\n");
1164
1165 auto vt = elements[0]->Type();
1166 if (vt->Kind() != rvsdg::TypeKind::Value)
1167 throw util::Error("expected value Type.\n");
1168
1169 auto op = std::make_unique<ConstantArrayOperation>(vt, elements.size());
1170 return ThreeAddressCode::create(std::move(op), elements);
1171 }
1172
1173 static rvsdg::Output *
1174 Create(const std::vector<rvsdg::Output *> & operands)
1175 {
1176 if (operands.empty())
1177 throw util::Error("Expected at least one element.\n");
1178
1179 auto valueType = operands[0]->Type();
1180 if (valueType->Kind() != rvsdg::TypeKind::Value)
1181 {
1182 throw util::Error("Expected value type.\n");
1183 }
1184
1185 return rvsdg::CreateOpNode<ConstantArrayOperation>(operands, valueType, operands.size())
1186 .output(0);
1187 }
1188};
1189
1191{
1192public:
1194
1195 explicit ConstantAggregateZeroOperation(std::shared_ptr<const rvsdg::Type> type)
1196 : SimpleOperation({}, { type })
1197 {
1198 auto st = dynamic_cast<const StructType *>(type.get());
1199 auto at = dynamic_cast<const ArrayType *>(type.get());
1200 auto vt = dynamic_cast<const VectorType *>(type.get());
1201 if (!st && !at && !vt)
1202 throw util::Error("expected array, struct, or vector type.\n");
1203 }
1204
1205 bool
1206 operator==(const Operation & other) const noexcept override;
1207
1208 [[nodiscard]] std::string
1209 debug_string() const override;
1210
1211 [[nodiscard]] std::unique_ptr<Operation>
1212 copy() const override;
1213
1214 static std::unique_ptr<llvm::ThreeAddressCode>
1215 create(std::shared_ptr<const jlm::rvsdg::Type> type)
1216 {
1217 auto op = std::make_unique<ConstantAggregateZeroOperation>(std::move(type));
1218 return ThreeAddressCode::create(std::move(op), {});
1219 }
1220
1221 static rvsdg::SimpleNode &
1222 createNode(rvsdg::Region & region, std::shared_ptr<const rvsdg::Type> type)
1223 {
1224 return rvsdg::CreateOpNode<ConstantAggregateZeroOperation>(region, std::move(type));
1225 }
1226
1227 static rvsdg::Output *
1228 Create(rvsdg::Region & region, const std::shared_ptr<const rvsdg::Type> & type)
1229 {
1230 return createNode(region, type).output(0);
1231 }
1232};
1233
1235{
1236public:
1237 ~ExtractElementOperation() noexcept override;
1238
1240 const std::shared_ptr<const VectorType> & vtype,
1241 const std::shared_ptr<const jlm::rvsdg::BitType> & btype)
1242 : SimpleOperation({ vtype, btype }, { vtype->Type() })
1243 {}
1244
1245 bool
1246 operator==(const Operation & other) const noexcept override;
1247
1248 [[nodiscard]] std::string
1249 debug_string() const override;
1250
1251 [[nodiscard]] std::unique_ptr<Operation>
1252 copy() const override;
1253
1254 static inline std::unique_ptr<llvm::ThreeAddressCode>
1255 create(const llvm::Variable * vector, const llvm::Variable * index)
1256 {
1257 auto vt = std::dynamic_pointer_cast<const VectorType>(vector->Type());
1258 if (!vt)
1259 throw util::Error("expected vector type.");
1260
1261 auto bt = std::dynamic_pointer_cast<const jlm::rvsdg::BitType>(index->Type());
1262 if (!bt)
1263 throw util::Error("expected bit type.");
1264
1265 auto op = std::make_unique<ExtractElementOperation>(vt, bt);
1266 return ThreeAddressCode::create(std::move(op), { vector, index });
1267 }
1268};
1269
1271{
1272public:
1273 ~ShuffleVectorOperation() noexcept override;
1274
1276 const std::shared_ptr<const FixedVectorType> & v,
1277 const std::vector<int> & mask)
1278 : SimpleOperation({ v, v }, { v }),
1279 Mask_(mask)
1280 {}
1281
1283 const std::shared_ptr<const ScalableVectorType> & v,
1284 const std::vector<int> & mask)
1285 : SimpleOperation({ v, v }, { v }),
1286 Mask_(mask)
1287 {}
1288
1289 bool
1290 operator==(const Operation & other) const noexcept override;
1291
1292 [[nodiscard]] std::string
1293 debug_string() const override;
1294
1295 [[nodiscard]] std::unique_ptr<Operation>
1296 copy() const override;
1297
1298 const ::llvm::ArrayRef<int>
1299 Mask() const
1300 {
1301 return Mask_;
1302 }
1303
1304 static std::unique_ptr<llvm::ThreeAddressCode>
1305 create(const Variable * v1, const Variable * v2, const std::vector<int> & mask)
1306 {
1307 if (is<FixedVectorType>(v1->type()) && is<FixedVectorType>(v2->type()))
1308 return CreateShuffleVectorTac<FixedVectorType>(v1, v2, mask);
1309
1310 if (is<ScalableVectorType>(v1->type()) && is<ScalableVectorType>(v2->type()))
1311 return CreateShuffleVectorTac<ScalableVectorType>(v1, v2, mask);
1312
1313 throw util::Error("Expected vector types as operands.");
1314 }
1315
1316private:
1317 template<typename T>
1318 static std::unique_ptr<ThreeAddressCode>
1319 CreateShuffleVectorTac(const Variable * v1, const Variable * v2, const std::vector<int> & mask)
1320 {
1321 auto vt = std::static_pointer_cast<const T>(v1->Type());
1322 auto op = std::make_unique<ShuffleVectorOperation>(vt, mask);
1323 return ThreeAddressCode::create(std::move(op), { v1, v2 });
1324 }
1325
1326 std::vector<int> Mask_;
1327};
1328
1330{
1331public:
1332 ~ConstantVectorOperation() noexcept override;
1333
1334 explicit ConstantVectorOperation(const std::shared_ptr<const VectorType> & vt)
1335 : SimpleOperation({ vt->size(), vt->Type() }, { vt })
1336 {}
1337
1338 bool
1339 operator==(const Operation & other) const noexcept override;
1340
1341 [[nodiscard]] std::string
1342 debug_string() const override;
1343
1344 [[nodiscard]] std::unique_ptr<Operation>
1345 copy() const override;
1346
1347 static inline std::unique_ptr<llvm::ThreeAddressCode>
1349 const std::vector<const Variable *> & operands,
1350 const std::shared_ptr<const jlm::rvsdg::Type> & type)
1351 {
1352 auto vt = std::dynamic_pointer_cast<const VectorType>(type);
1353 if (!vt)
1354 throw util::Error("expected vector type.");
1355
1356 auto op = std::make_unique<ConstantVectorOperation>(vt);
1357 return ThreeAddressCode::create(std::move(op), operands);
1358 }
1359};
1360
1362{
1363public:
1364 ~InsertElementOperation() noexcept override;
1365
1367 const std::shared_ptr<const VectorType> & vectype,
1368 const std::shared_ptr<const jlm::rvsdg::Type> & vtype,
1369 const std::shared_ptr<const jlm::rvsdg::BitType> & btype)
1370 : SimpleOperation({ vectype, vtype, btype }, { vectype })
1371 {
1372 if (vectype->type() != *vtype)
1373 {
1374 auto received = vtype->debug_string();
1375 auto expected = vectype->type().debug_string();
1376 throw util::Error(jlm::util::strfmt("expected ", expected, ", got ", received));
1377 }
1378 }
1379
1380 bool
1381 operator==(const Operation & other) const noexcept override;
1382
1383 [[nodiscard]] std::string
1384 debug_string() const override;
1385
1386 [[nodiscard]] std::unique_ptr<Operation>
1387 copy() const override;
1388
1389 static inline std::unique_ptr<llvm::ThreeAddressCode>
1390 create(const llvm::Variable * vector, const llvm::Variable * value, const llvm::Variable * index)
1391 {
1392 auto vct = std::dynamic_pointer_cast<const VectorType>(vector->Type());
1393 if (!vct)
1394 throw util::Error("expected vector type.");
1395
1396 auto vt = value->Type();
1397 if (vt->Kind() != rvsdg::TypeKind::Value)
1398 throw util::Error("expected value type.");
1399
1400 auto bt = std::dynamic_pointer_cast<const jlm::rvsdg::BitType>(index->Type());
1401 if (!bt)
1402 throw util::Error("expected bit type.");
1403
1404 auto op = std::make_unique<InsertElementOperation>(vct, vt, bt);
1405 return ThreeAddressCode::create(std::move(op), { vector, value, index });
1406 }
1407};
1408
1410{
1411public:
1412 ~VectorUnaryOperation() noexcept override;
1413
1415 const rvsdg::UnaryOperation & op,
1416 const std::shared_ptr<const VectorType> & operand,
1417 const std::shared_ptr<const VectorType> & result)
1418 : SimpleOperation({ operand }, { result }),
1419 op_(op.copy())
1420 {
1421 // Bit casts can convert between vectors of different length, or between scalars and vectors,
1422 // so it should not be seen as a vector operation performed lane-wise.
1423 JLM_ASSERT(!is<BitCastOperation>(op));
1424
1425 if (operand->type() != *op.argument(0))
1426 {
1427 auto received = operand->type().debug_string();
1428 auto expected = op.argument(0)->debug_string();
1429 throw util::Error(jlm::util::strfmt("expected ", expected, ", got ", received));
1430 }
1431
1432 if (result->type() != *op.result(0))
1433 {
1434 auto received = result->type().debug_string();
1435 auto expected = op.result(0)->debug_string();
1436 throw util::Error(jlm::util::strfmt("expected ", expected, ", got ", received));
1437 }
1438 }
1439
1441 : SimpleOperation(other),
1442 op_(other.op_->copy())
1443 {}
1444
1446 : SimpleOperation(other),
1447 op_(std::move(other.op_))
1448 {}
1449
1452 {
1453 if (this != &other)
1454 op_ = other.op_->copy();
1455
1456 return *this;
1457 }
1458
1461 {
1462 if (this != &other)
1463 op_ = std::move(other.op_);
1464
1465 return *this;
1466 }
1467
1468 const rvsdg::UnaryOperation &
1469 operation() const noexcept
1470 {
1471 return *static_cast<const rvsdg::UnaryOperation *>(op_.get());
1472 }
1473
1474 bool
1475 operator==(const Operation & other) const noexcept override;
1476
1477 [[nodiscard]] std::string
1478 debug_string() const override;
1479
1480 [[nodiscard]] std::unique_ptr<Operation>
1481 copy() const override;
1482
1483 static inline std::unique_ptr<llvm::ThreeAddressCode>
1485 const rvsdg::UnaryOperation & unop,
1486 const llvm::Variable * operand,
1487 const std::shared_ptr<const jlm::rvsdg::Type> & type)
1488 {
1489 auto vct1 = std::dynamic_pointer_cast<const VectorType>(operand->Type());
1490 auto vct2 = std::dynamic_pointer_cast<const VectorType>(type);
1491 if (!vct1 || !vct2)
1492 throw util::Error("expected vector type.");
1493
1494 auto op = std::make_unique<VectorUnaryOperation>(unop, vct1, vct2);
1495 return ThreeAddressCode::create(std::move(op), { operand });
1496 }
1497
1498private:
1499 std::unique_ptr<Operation> op_;
1500};
1501
1503{
1504public:
1505 ~VectorBinaryOperation() noexcept override;
1506
1508 const rvsdg::BinaryOperation & binop,
1509 const std::shared_ptr<const VectorType> & op1,
1510 const std::shared_ptr<const VectorType> & op2,
1511 const std::shared_ptr<const VectorType> & result)
1512 : SimpleOperation({ op1, op2 }, { result }),
1513 op_(binop.copy())
1514 {
1515 if (*op1 != *op2)
1516 throw util::Error("expected the same vector types.");
1517
1518 if (op1->type() != *binop.argument(0))
1519 {
1520 auto received = op1->type().debug_string();
1521 auto expected = binop.argument(0)->debug_string();
1522 throw util::Error(jlm::util::strfmt("expected ", expected, ", got ", received));
1523 }
1524
1525 if (result->type() != *binop.result(0))
1526 {
1527 auto received = result->type().debug_string();
1528 auto expected = binop.result(0)->debug_string();
1529 throw util::Error(jlm::util::strfmt("expected ", expected, ", got ", received));
1530 }
1531 }
1532
1534 : SimpleOperation(other),
1535 op_(other.op_->copy())
1536 {}
1537
1539 : SimpleOperation(other),
1540 op_(std::move(other.op_))
1541 {}
1542
1545 {
1546 if (this != &other)
1547 op_ = other.op_->copy();
1548
1549 return *this;
1550 }
1551
1554 {
1555 if (this != &other)
1556 op_ = std::move(other.op_);
1557
1558 return *this;
1559 }
1560
1562 operation() const noexcept
1563 {
1564 return *static_cast<const rvsdg::BinaryOperation *>(op_.get());
1565 }
1566
1567 bool
1568 operator==(const Operation & other) const noexcept override;
1569
1570 [[nodiscard]] std::string
1571 debug_string() const override;
1572
1573 [[nodiscard]] std::unique_ptr<Operation>
1574 copy() const override;
1575
1576 static inline std::unique_ptr<llvm::ThreeAddressCode>
1578 const rvsdg::BinaryOperation & binop,
1579 const llvm::Variable * op1,
1580 const llvm::Variable * op2,
1581 const std::shared_ptr<const jlm::rvsdg::Type> & type)
1582 {
1583 auto vct1 = std::dynamic_pointer_cast<const VectorType>(op1->Type());
1584 auto vct2 = std::dynamic_pointer_cast<const VectorType>(op2->Type());
1585 auto vct3 = std::dynamic_pointer_cast<const VectorType>(type);
1586 if (!vct1 || !vct2 || !vct3)
1587 throw util::Error("expected vector type.");
1588
1589 auto op = std::make_unique<VectorBinaryOperation>(binop, vct1, vct2, vct3);
1590 return ThreeAddressCode::create(std::move(op), { op1, op2 });
1591 }
1592
1593private:
1594 std::unique_ptr<Operation> op_;
1595};
1596
1598{
1599public:
1600 ~ConstantDataVectorOperation() noexcept override;
1601
1602private:
1603 explicit ConstantDataVectorOperation(const std::shared_ptr<const VectorType> & vt)
1604 : SimpleOperation({ vt->size(), vt->Type() }, { vt })
1605 {}
1606
1607public:
1608 bool
1609 operator==(const Operation & other) const noexcept override;
1610
1611 [[nodiscard]] std::string
1612 debug_string() const override;
1613
1614 [[nodiscard]] std::unique_ptr<Operation>
1615 copy() const override;
1616
1617 size_t
1618 size() const noexcept
1619 {
1620 return std::static_pointer_cast<const VectorType>(result(0))->size();
1621 }
1622
1623 const jlm::rvsdg::Type &
1624 type() const noexcept
1625 {
1626 return std::static_pointer_cast<const VectorType>(result(0))->type();
1627 }
1628
1629 static std::unique_ptr<ThreeAddressCode>
1630 Create(const std::vector<const Variable *> & elements)
1631 {
1632 if (elements.empty())
1633 throw util::Error("Expected at least one element.");
1634
1635 auto vt = elements[0]->Type();
1636 if (vt->Kind() != rvsdg::TypeKind::Value)
1637 throw util::Error("Expected value type.");
1638
1639 auto op = std::unique_ptr<ConstantDataVectorOperation>(
1641 return ThreeAddressCode::create(std::move(op), elements);
1642 }
1643};
1644
1651{
1652public:
1653 ~MallocOperation() noexcept override;
1654
1655 explicit MallocOperation(std::shared_ptr<const rvsdg::BitType> type)
1657 { std::move(type), IOStateType::Create() },
1659 {}
1660
1661 bool
1662 operator==(const Operation & other) const noexcept override;
1663
1664 [[nodiscard]] std::string
1665 debug_string() const override;
1666
1667 [[nodiscard]] std::unique_ptr<Operation>
1668 copy() const override;
1669
1670 const rvsdg::BitType &
1671 getSizeType() const noexcept
1672 {
1673 return *std::static_pointer_cast<const rvsdg::BitType>(argument(0));
1674 }
1675
1678 {
1679 JLM_ASSERT(narguments() == 2 && nresults() == 3);
1680 return rvsdg::FunctionType({ argument(0), argument(1) }, { result(0), result(1), result(2) });
1681 }
1682
1683 static rvsdg::Input &
1685 {
1686 JLM_ASSERT(is<MallocOperation>(node.GetOperation()));
1687 auto & size = *node.input(0);
1688 JLM_ASSERT(is<rvsdg::BitType>(size.Type()));
1689 return size;
1690 }
1691
1692 static rvsdg::Input &
1694 {
1695 JLM_ASSERT(is<MallocOperation>(node.GetOperation()));
1696 auto & ioState = *node.input(1);
1697 JLM_ASSERT(is<IOStateType>(ioState.Type()));
1698 return ioState;
1699 }
1700
1701 static rvsdg::Output &
1703 {
1704 JLM_ASSERT(is<MallocOperation>(node.GetOperation()));
1705 auto & address = *node.output(0);
1706 JLM_ASSERT(is<PointerType>(address.Type()));
1707 return address;
1708 }
1709
1710 static rvsdg::Output &
1712 {
1713 JLM_ASSERT(is<MallocOperation>(node.GetOperation()));
1714 auto & ioState = *node.output(1);
1715 JLM_ASSERT(is<IOStateType>(ioState.Type()));
1716 return ioState;
1717 }
1718
1719 static rvsdg::Output &
1721 {
1722 JLM_ASSERT(is<MallocOperation>(node.GetOperation()));
1723 auto & memoryState = *node.output(2);
1724 JLM_ASSERT(is<MemoryStateType>(memoryState.Type()));
1725 return memoryState;
1726 }
1727
1728 static std::unique_ptr<ThreeAddressCode>
1729 createTac(const Variable * size, const Variable * ioState)
1730 {
1731 auto bitType = checkAndExtractSizeType(size->Type());
1732 auto op = std::make_unique<MallocOperation>(std::move(bitType));
1733 return ThreeAddressCode::create(std::move(op), { size, ioState });
1734 }
1735
1736 static rvsdg::SimpleNode &
1738 {
1739 auto bitType = checkAndExtractSizeType(size.Type());
1740 return rvsdg::CreateOpNode<MallocOperation>({ &size, &ioState }, std::move(bitType));
1741 }
1742
1743private:
1744 static std::shared_ptr<const rvsdg::BitType>
1745 checkAndExtractSizeType(const std::shared_ptr<const rvsdg::Type> & type)
1746 {
1747 if (auto bitType = std::dynamic_pointer_cast<const rvsdg::BitType>(type))
1748 return bitType;
1749
1750 throw std::runtime_error("Expected bits type.");
1751 }
1752};
1753
1760{
1761public:
1762 ~FreeOperation() noexcept override;
1763
1767
1768 bool
1769 operator==(const Operation & other) const noexcept override;
1770
1771 [[nodiscard]] std::string
1772 debug_string() const override;
1773
1774 [[nodiscard]] std::unique_ptr<Operation>
1775 copy() const override;
1776
1777 [[nodiscard]] size_t
1778 numMemoryStates() const noexcept
1779 {
1780 JLM_ASSERT(nresults() >= 1);
1781 return nresults() - 1;
1782 }
1783
1788 [[nodiscard]] static rvsdg::Input &
1789 getAddressInput(const rvsdg::Node & node) noexcept
1790 {
1791 JLM_ASSERT(is<FreeOperation>(&node));
1792 const auto input = node.input(0);
1793 JLM_ASSERT(is<PointerType>(input->Type()));
1794 return *input;
1795 }
1796
1797 [[nodiscard]] static rvsdg::Input &
1798 getIOStateInput(const rvsdg::Node & node) noexcept
1799 {
1800 JLM_ASSERT(is<FreeOperation>(&node));
1801 const auto input = node.input(1);
1802 JLM_ASSERT(is<IOStateType>(input->Type()));
1803 return *input;
1804 }
1805
1806 [[nodiscard]] static rvsdg::Output &
1807 getIOStateOutput(const rvsdg::Node & node) noexcept
1808 {
1809 JLM_ASSERT(is<FreeOperation>(&node));
1810 const auto output = node.output(0);
1811 JLM_ASSERT(is<IOStateType>(output->Type()));
1812 return *output;
1813 }
1814
1815 [[nodiscard]] static rvsdg::Input &
1817 {
1818 JLM_ASSERT(is<MemoryStateType>(output.Type()));
1819 auto [freeNode, freeOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<FreeOperation>(output);
1820 JLM_ASSERT(freeOperation);
1821 const auto input = freeNode->input(output.index() + 1);
1822 JLM_ASSERT(is<MemoryStateType>(input->Type()));
1823 return *input;
1824 }
1825
1826 [[nodiscard]] static rvsdg::Node::OutputIteratorRange
1827 memoryStateOutputs(const rvsdg::Node & node) noexcept
1828 {
1829 const auto freeOperation = util::assertedCast<const FreeOperation>(&node.GetOperation());
1830 if (freeOperation->numMemoryStates() == 0)
1831 {
1832 return { rvsdg::Output::Iterator(nullptr), rvsdg::Output::Iterator(nullptr) };
1833 }
1834
1835 const auto firstMemoryStateOutput = node.output(1);
1836 JLM_ASSERT(is<MemoryStateType>(firstMemoryStateOutput->Type()));
1837 return { rvsdg::Output::Iterator(firstMemoryStateOutput), rvsdg::Output::Iterator(nullptr) };
1838 }
1839
1840 static std::unique_ptr<ThreeAddressCode>
1842 const Variable * pointer,
1843 const Variable * iOState,
1844 const std::vector<const Variable *> & memoryStates)
1845 {
1846 std::vector<const Variable *> operands;
1847 operands.push_back(pointer);
1848 operands.push_back(iOState);
1849 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
1850
1851 auto operation = std::make_unique<FreeOperation>(memoryStates.size());
1852 return ThreeAddressCode::create(std::move(operation), operands);
1853 }
1854
1855 static rvsdg::SimpleNode &
1857 rvsdg::Output & pointer,
1858 rvsdg::Output & iOState,
1859 const std::vector<rvsdg::Output *> & memoryStates)
1860 {
1861 std::vector<rvsdg::Output *> operands;
1862 operands.push_back(&pointer);
1863 operands.push_back(&iOState);
1864 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
1865
1866 return rvsdg::CreateOpNode<FreeOperation>(operands, memoryStates.size());
1867 }
1868
1869 static std::vector<rvsdg::Output *>
1871 rvsdg::Output & pointer,
1872 rvsdg::Output & IOState,
1873 const std::vector<rvsdg::Output *> & memoryStates)
1874 {
1875 return outputs(&createNode(pointer, IOState, memoryStates));
1876 }
1877
1878private:
1879 static std::vector<std::shared_ptr<const rvsdg::Type>>
1881 {
1882 std::vector<std::shared_ptr<const rvsdg::Type>> types(
1884 types.insert(types.end(), numMemoryStates, MemoryStateType::Create());
1885
1886 return types;
1887 }
1888
1889 static std::vector<std::shared_ptr<const rvsdg::Type>>
1891 {
1892 std::vector<std::shared_ptr<const rvsdg::Type>> types({ IOStateType::Create() });
1893 types.insert(types.end(), numMemoryStates, MemoryStateType::Create());
1894
1895 return types;
1896 }
1897};
1898}
1899
1900#endif
std::int64_t expected
static const auto vt
Definition PullTests.cpp:16
util::HashSet< rvsdg::Output * > arguments
static std::shared_ptr< const ArrayType > Create(std::shared_ptr< const Type > type, size_t nelements)
Definition types.hpp:98
std::unique_ptr< Operation > copy() const override
Definition operators.cpp:69
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *rhs, const Variable *lhs)
~AssignmentOperation() noexcept override
std::string debug_string() const override
Definition operators.cpp:63
AssignmentOperation(const AssignmentOperation &)=default
AssignmentOperation(AssignmentOperation &&)=default
bool operator==(const Operation &other) const noexcept override
Definition operators.cpp:56
std::string debug_string() const override
size_t nalternatives() const noexcept
~BranchOperation() noexcept override
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< llvm::ThreeAddressCode > create(size_t nalternatives, const Variable *operand)
bool operator==(const Operation &other) const noexcept override
static rvsdg::SimpleNode & createNode(rvsdg::Region &region, std::shared_ptr< const rvsdg::Type > type)
std::unique_ptr< Operation > copy() const override
static rvsdg::Output * Create(rvsdg::Region &region, const std::shared_ptr< const rvsdg::Type > &type)
static std::unique_ptr< llvm::ThreeAddressCode > create(std::shared_ptr< const jlm::rvsdg::Type > type)
~ConstantAggregateZeroOperation() noexcept override
bool operator==(const Operation &other) const noexcept override
std::string debug_string() const override
~ConstantArrayOperation() noexcept override
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &elements)
bool operator==(const Operation &other) const noexcept override
std::string debug_string() const override
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &operands)
std::shared_ptr< const ArrayType > type() const noexcept
size_t size() const noexcept
~ConstantDataArrayOperation() noexcept override
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &elements)
std::unique_ptr< Operation > copy() const override
std::string debug_string() const override
static std::unique_ptr< ThreeAddressCode > create(const std::vector< const Variable * > &elements)
bool operator==(const Operation &other) const noexcept override
std::shared_ptr< const ArrayType > type() const noexcept
bool operator==(const Operation &other) const noexcept override
~ConstantDataVectorOperation() noexcept override
std::unique_ptr< Operation > copy() const override
const jlm::rvsdg::Type & type() const noexcept
static std::unique_ptr< ThreeAddressCode > Create(const std::vector< const Variable * > &elements)
std::string debug_string() const override
~ConstantFP() noexcept override
static std::unique_ptr< ConstantFP > create(const ::llvm::APFloat &constant, const std::shared_ptr< const jlm::rvsdg::Type > &type)
static std::unique_ptr< llvm::ThreeAddressCode > createTac(const ::llvm::APFloat &constant, const std::shared_ptr< const jlm::rvsdg::Type > &type)
static rvsdg::Node & createNode(rvsdg::Region &region, fpsize size, const ::llvm::APFloat &constant)
ConstantFP(std::shared_ptr< const FloatingPointType > fpt, const ::llvm::APFloat &constant)
const fpsize & size() const noexcept
std::unique_ptr< Operation > copy() const override
::llvm::APFloat constant_
bool operator==(const Operation &other) const noexcept override
std::string debug_string() const override
const ::llvm::APFloat & constant() const noexcept
static ::llvm::APFloat getZeroRepresentation(fpsize size)
ConstantPointerNullOperation class.
std::string debug_string() const override
static rvsdg::Node & createNode(rvsdg::Region &region)
static std::unique_ptr< ThreeAddressCode > createTac()
bool operator==(const Operation &other) const noexcept override
~ConstantPointerNullOperation() noexcept override
std::unique_ptr< Operation > copy() const override
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< ThreeAddressCode > create(const std::vector< const Variable * > &elements, const std::shared_ptr< const rvsdg::Type > &type)
static std::vector< std::shared_ptr< const rvsdg::Type > > create_srctypes(const StructType &type)
static rvsdg::Output & Create(rvsdg::Region &, const std::vector< rvsdg::Output * > &operands, std::shared_ptr< const rvsdg::Type > resultType)
static std::shared_ptr< const StructType > CheckAndExtractStructType(std::shared_ptr< const rvsdg::Type > type)
~ConstantStructOperation() noexcept override
std::string debug_string() const override
const StructType & type() const noexcept
bool operator==(const Operation &other) const noexcept override
bool operator==(const Operation &other) const noexcept override
std::unique_ptr< Operation > copy() const override
~ConstantVectorOperation() noexcept override
std::string debug_string() const override
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &operands, const std::shared_ptr< const jlm::rvsdg::Type > &type)
std::string debug_string() const override
static std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::Variable *vector, const llvm::Variable *index)
bool operator==(const Operation &other) const noexcept override
~ExtractElementOperation() noexcept override
std::unique_ptr< Operation > copy() const override
std::string debug_string() const override
jlm::rvsdg::binop_reduction_path_t can_reduce_operand_pair(const jlm::rvsdg::Output *op1, const jlm::rvsdg::Output *op2) const noexcept override
const llvm::fpop & fpop() const noexcept
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::fpop &fpop, const Variable *op1, const Variable *op2)
static std::optional< std::vector< rvsdg::Output * > > foldConstants(const FBinaryOperation &operation, const std::vector< rvsdg::Output * > &operands)
const fpsize & size() const noexcept
FBinaryOperation(const llvm::fpop &op, const std::shared_ptr< const FloatingPointType > &fpt)
jlm::rvsdg::Output * reduce_operand_pair(jlm::rvsdg::binop_reduction_path_t path, jlm::rvsdg::Output *op1, jlm::rvsdg::Output *op2) const override
~FBinaryOperation() noexcept override
bool operator==(const Operation &other) const noexcept override
const fpcmp & cmp() const noexcept
jlm::rvsdg::binop_reduction_path_t can_reduce_operand_pair(const jlm::rvsdg::Output *op1, const jlm::rvsdg::Output *op2) const noexcept override
static std::unique_ptr< llvm::ThreeAddressCode > create(const fpcmp &cmp, const Variable *op1, const Variable *op2)
const fpsize & size() const noexcept
~FCmpOperation() noexcept override
FCmpOperation(const fpcmp &cmp, const std::shared_ptr< const FloatingPointType > &fpt)
std::string debug_string() const override
bool operator==(const Operation &other) const noexcept override
jlm::rvsdg::Output * reduce_operand_pair(jlm::rvsdg::binop_reduction_path_t path, jlm::rvsdg::Output *op1, jlm::rvsdg::Output *op2) const override
std::unique_ptr< Operation > copy() const override
static std::optional< std::vector< rvsdg::Output * > > foldConstants(const FCmpOperation &operation, const std::vector< rvsdg::Output * > &operands)
bool operator==(const Operation &other) const noexcept override
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *operand)
~FNegOperation() noexcept override
std::string debug_string() const override
const fpsize & size() const noexcept
FNegOperation(const std::shared_ptr< const FloatingPointType > &fpt)
static std::shared_ptr< const FixedVectorType > Create(std::shared_ptr< const rvsdg::Type > type, size_t size)
Definition types.hpp:413
static std::shared_ptr< const FloatingPointType > Create(fpsize size)
Definition types.cpp:117
static rvsdg::Input & getAddressInput(const rvsdg::Node &node) noexcept
static std::vector< rvsdg::Output * > Create(rvsdg::Output &pointer, rvsdg::Output &IOState, const std::vector< rvsdg::Output * > &memoryStates)
static rvsdg::Node::OutputIteratorRange memoryStateOutputs(const rvsdg::Node &node) noexcept
static rvsdg::Input & getIOStateInput(const rvsdg::Node &node) noexcept
size_t numMemoryStates() const noexcept
static rvsdg::Output & getIOStateOutput(const rvsdg::Node &node) noexcept
static rvsdg::Input & mapMemoryStateOutputToInput(rvsdg::Output &output) noexcept
bool operator==(const Operation &other) const noexcept override
static std::unique_ptr< ThreeAddressCode > Create(const Variable *pointer, const Variable *iOState, const std::vector< const Variable * > &memoryStates)
static rvsdg::SimpleNode & createNode(rvsdg::Output &pointer, rvsdg::Output &iOState, const std::vector< rvsdg::Output * > &memoryStates)
std::unique_ptr< Operation > copy() const override
static std::vector< std::shared_ptr< const rvsdg::Type > > createOperandTypes(const size_t numMemoryStates)
static std::vector< std::shared_ptr< const rvsdg::Type > > createResultTypes(const size_t numMemoryStates)
~FreeOperation() noexcept override
std::string debug_string() const override
FreezeOperation class.
static std::unique_ptr< llvm::ThreeAddressCode > createTac(const Variable &operand)
std::string debug_string() const override
~FreezeOperation() noexcept override
std::unique_ptr< Operation > copy() const override
static jlm::rvsdg::Node & createNode(jlm::rvsdg::Output &operand)
const jlm::rvsdg::Type & getType() const noexcept
bool operator==(const Operation &other) const noexcept override
static std::shared_ptr< const IOStateType > Create()
Definition types.cpp:343
static std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::Variable *vector, const llvm::Variable *value, const llvm::Variable *index)
bool operator==(const Operation &other) const noexcept override
std::string debug_string() const override
~InsertElementOperation() noexcept override
std::unique_ptr< Operation > copy() const override
bool operator==(const Operation &other) const noexcept override
std::unique_ptr< Operation > copy() const override
std::string debug_string() const override
~MallocOperation() noexcept override
static std::unique_ptr< ThreeAddressCode > createTac(const Variable *size, const Variable *ioState)
static rvsdg::Output & addressOutput(const rvsdg::Node &node)
const rvsdg::BitType & getSizeType() const noexcept
static rvsdg::Input & sizeInput(const rvsdg::Node &node)
static rvsdg::Output & memoryStateOutput(const rvsdg::Node &node)
static rvsdg::SimpleNode & createNode(rvsdg::Output &size, rvsdg::Output &ioState)
static std::shared_ptr< const rvsdg::BitType > checkAndExtractSizeType(const std::shared_ptr< const rvsdg::Type > &type)
static rvsdg::Input & ioStateInput(const rvsdg::Node &node)
rvsdg::FunctionType getFunctionType() const
static rvsdg::Output & ioStateOutput(const rvsdg::Node &node)
static std::shared_ptr< const MemoryStateType > Create()
Definition types.cpp:379
PointerType class.
Definition types.hpp:25
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
PoisonValueOperation class.
bool operator==(const Operation &other) const noexcept override
PoisonValueOperation(PoisonValueOperation &&)=delete
~PoisonValueOperation() noexcept override
const jlm::rvsdg::Type & GetType() const noexcept
std::string debug_string() const override
PoisonValueOperation & operator=(const PoisonValueOperation &)=delete
static std::unique_ptr< llvm::ThreeAddressCode > Create(const std::shared_ptr< const jlm::rvsdg::Type > &type)
static jlm::rvsdg::Output * Create(rvsdg::Region *region, const std::shared_ptr< const jlm::rvsdg::Type > &type)
static std::shared_ptr< const jlm::rvsdg::Type > CheckAndConvertType(const std::shared_ptr< const jlm::rvsdg::Type > &type)
PoisonValueOperation & operator=(PoisonValueOperation &&)=delete
PoisonValueOperation(const PoisonValueOperation &)=default
std::unique_ptr< Operation > copy() const override
~PtrCmpOperation() noexcept override
static std::unique_ptr< llvm::ThreeAddressCode > create(ICmpPredicate predicateKind, const Variable *op1, const Variable *op2)
bool operator==(const Operation &other) const noexcept override
ICmpPredicate predicate() const noexcept
jlm::rvsdg::binop_reduction_path_t can_reduce_operand_pair(const jlm::rvsdg::Output *op1, const jlm::rvsdg::Output *op2) const noexcept override
std::string debug_string() const override
jlm::rvsdg::Output * reduce_operand_pair(jlm::rvsdg::binop_reduction_path_t path, jlm::rvsdg::Output *op1, jlm::rvsdg::Output *op2) const override
static rvsdg::SimpleNode & createNode(const ICmpPredicate kind, rvsdg::Output &operand1, rvsdg::Output &operand2)
static std::optional< std::vector< rvsdg::Output * > > normalizeIdenticalOperands(const PtrCmpOperation &ptrCmpOperation, const std::vector< rvsdg::Output * > &operands)
std::unique_ptr< Operation > copy() const override
static std::optional< std::vector< rvsdg::Output * > > normalizeNullPointerComparison(const PtrCmpOperation &ptrCmpOperation, const std::vector< rvsdg::Output * > &operands)
const std::shared_ptr< const jlm::rvsdg::Type > & Type() const noexcept
bool operator==(const Operation &other) const noexcept override
Definition operators.cpp:77
static std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::Variable *p, const llvm::Variable *t, const llvm::Variable *f)
const jlm::rvsdg::Type & type() const noexcept
std::string debug_string() const override
Definition operators.cpp:84
std::unique_ptr< Operation > copy() const override
Definition operators.cpp:90
~SelectOperation() noexcept override
std::string debug_string() const override
static std::unique_ptr< ThreeAddressCode > CreateShuffleVectorTac(const Variable *v1, const Variable *v2, const std::vector< int > &mask)
std::unique_ptr< Operation > copy() const override
ShuffleVectorOperation(const std::shared_ptr< const ScalableVectorType > &v, const std::vector< int > &mask)
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *v1, const Variable *v2, const std::vector< int > &mask)
const ::llvm::ArrayRef< int > Mask() const
bool operator==(const Operation &other) const noexcept override
~ShuffleVectorOperation() noexcept override
SsaPhiOperation & operator=(SsaPhiOperation &&)=delete
SsaPhiOperation & operator=(const SsaPhiOperation &)=delete
SsaPhiOperation(const SsaPhiOperation &)=default
ControlFlowGraphNode * GetIncomingNode(size_t n) const noexcept
Definition operators.hpp:70
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< std::pair< const Variable *, ControlFlowGraphNode * > > &arguments, std::shared_ptr< const jlm::rvsdg::Type > type)
Definition operators.hpp:77
std::string debug_string() const override
Definition operators.cpp:33
bool operator==(const Operation &other) const noexcept override
Definition operators.cpp:26
std::unique_ptr< Operation > copy() const override
Definition operators.cpp:48
~SsaPhiOperation() noexcept override
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition operators.hpp:64
std::vector< ControlFlowGraphNode * > IncomingNodes_
Definition operators.hpp:94
StructType class.
Definition types.hpp:184
std::string debug_string() const override
Definition types.cpp:229
size_t numElements() const noexcept
Definition types.hpp:230
std::shared_ptr< const Type > getElementType(const size_t index) const noexcept
Definition types.hpp:236
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition tac.hpp:155
UndefValueOperation class.
~UndefValueOperation() noexcept override
std::string debug_string() const override
const rvsdg::Type & GetType() const noexcept
UndefValueOperation(const UndefValueOperation &)=default
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< llvm::ThreeAddressCode > Create(std::unique_ptr< ThreeAddressCodeVariable > result)
static std::unique_ptr< llvm::ThreeAddressCode > Create(std::shared_ptr< const jlm::rvsdg::Type > type, const std::string &name)
bool operator==(const Operation &other) const noexcept override
UndefValueOperation & operator=(UndefValueOperation &&)=delete
UndefValueOperation & operator=(const UndefValueOperation &)=delete
static std::unique_ptr< llvm::ThreeAddressCode > Create(std::shared_ptr< const jlm::rvsdg::Type > type)
static jlm::rvsdg::Output * Create(rvsdg::Region &region, std::shared_ptr< const jlm::rvsdg::Type > type)
static std::shared_ptr< const VariableArgumentType > Create()
Definition types.cpp:180
const jlm::rvsdg::Type & type() const noexcept
Definition variable.hpp:56
const std::shared_ptr< const jlm::rvsdg::Type > Type() const noexcept
Definition variable.hpp:62
static rvsdg::Output * Create(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands)
VariadicArgumentListOperation(const VariadicArgumentListOperation &)=default
VariadicArgumentListOperation & operator=(const VariadicArgumentListOperation &)=delete
std::string debug_string() const override
~VariadicArgumentListOperation() noexcept override
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &arguments)
VariadicArgumentListOperation & operator=(VariadicArgumentListOperation &&)=delete
bool operator==(const Operation &other) const noexcept override
bool operator==(const Operation &other) const noexcept override
std::string debug_string() const override
VectorBinaryOperation & operator=(const VectorBinaryOperation &other)
std::unique_ptr< Operation > copy() const override
VectorBinaryOperation(const VectorBinaryOperation &other)
const rvsdg::BinaryOperation & operation() const noexcept
static std::unique_ptr< llvm::ThreeAddressCode > create(const rvsdg::BinaryOperation &binop, const llvm::Variable *op1, const llvm::Variable *op2, const std::shared_ptr< const jlm::rvsdg::Type > &type)
std::unique_ptr< Operation > op_
~VectorBinaryOperation() noexcept override
VectorBinaryOperation(VectorBinaryOperation &&other) noexcept
VectorBinaryOperation & operator=(VectorBinaryOperation &&other) noexcept
size_t size() const noexcept
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< ThreeAddressCode > createVectorSelectTac(const Variable *p, const Variable *t, const Variable *f)
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
std::string debug_string() const override
const rvsdg::Type & type() const noexcept
bool operator==(const Operation &other) const noexcept override
Definition operators.cpp:98
~VectorSelectOperation() noexcept override
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *p, const Variable *t, const Variable *f)
std::unique_ptr< Operation > op_
VectorUnaryOperation & operator=(VectorUnaryOperation &&other) noexcept
bool operator==(const Operation &other) const noexcept override
~VectorUnaryOperation() noexcept override
VectorUnaryOperation(const VectorUnaryOperation &other)
std::string debug_string() const override
const rvsdg::UnaryOperation & operation() const noexcept
VectorUnaryOperation(VectorUnaryOperation &&other) noexcept
std::unique_ptr< Operation > copy() const override
VectorUnaryOperation & operator=(const VectorUnaryOperation &other)
static std::unique_ptr< llvm::ThreeAddressCode > create(const rvsdg::UnaryOperation &unop, const llvm::Variable *operand, const std::shared_ptr< const jlm::rvsdg::Type > &type)
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
Function type class.
NodeInput * input(size_t index) const noexcept
Definition node.hpp:615
NodeOutput * output(size_t index) const noexcept
Definition node.hpp:650
virtual const Operation & GetOperation() const noexcept=0
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
NodeOutput * output(size_t index) const noexcept
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
SimpleOperation(std::vector< std::shared_ptr< const jlm::rvsdg::Type > > operands, std::vector< std::shared_ptr< const jlm::rvsdg::Type > > results)
Definition operation.hpp:61
size_t narguments() const noexcept
Definition operation.cpp:17
Unary operator.
Definition unary.hpp:24
UnaryOperation(std::shared_ptr< const Type > operand, std::shared_ptr< const Type > result)
Definition unary.hpp:28
#define JLM_ASSERT(x)
Definition common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition common.hpp:43
Global memory state passed between functions.
ICmpPredicate convertICmpPredicateToJlm(::llvm::CmpInst::Predicate predicate)
std::string_view iCmpPredicateToString(ICmpPredicate predicate)
::llvm::CmpInst::Predicate convertICmpPredicateToLlvm(ICmpPredicate predicate)
size_t binop_reduction_path_t
Definition binary.hpp:19
@ Value
Designate a value type.
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
static std::string strfmt(Args... args)
Definition strfmt.hpp:35