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
476 static std::optional<std::vector<rvsdg::Output *>>
478 const PtrCmpOperation & ptrCmpOperation,
479 const std::vector<rvsdg::Output *> & operands);
480
481private:
483};
484
485/* floating point constant operator */
486
488{
489public:
490 ~ConstantFP() noexcept override;
491
492 inline ConstantFP(const fpsize & size, const ::llvm::APFloat & constant)
495 {}
496
497 ConstantFP(std::shared_ptr<const FloatingPointType> fpt, const ::llvm::APFloat & constant)
498 : SimpleOperation({}, { std::move(fpt) }),
500 {}
501
502 bool
503 operator==(const Operation & other) const noexcept override;
504
505 [[nodiscard]] std::string
506 debug_string() const override;
507
508 [[nodiscard]] std::unique_ptr<Operation>
509 copy() const override;
510
511 inline const ::llvm::APFloat &
512 constant() const noexcept
513 {
514 return constant_;
515 }
516
517 inline const fpsize &
518 size() const noexcept
519 {
520 return std::static_pointer_cast<const FloatingPointType>(result(0))->size();
521 }
522
523 [[nodiscard]] static std::unique_ptr<ConstantFP>
524 create(const ::llvm::APFloat & constant, const std::shared_ptr<const jlm::rvsdg::Type> & type)
525 {
526 auto ft = std::dynamic_pointer_cast<const FloatingPointType>(type);
527 if (!ft)
528 throw util::Error("expected floating point type.");
529
530 return std::make_unique<ConstantFP>(std::move(ft), constant);
531 }
532
533 [[nodiscard]] static std::unique_ptr<llvm::ThreeAddressCode>
534 createTac(const ::llvm::APFloat & constant, const std::shared_ptr<const jlm::rvsdg::Type> & type)
535 {
536 return ThreeAddressCode::create(create(constant, type), {});
537 }
538
539 [[nodiscard]] static rvsdg::Node &
540 createNode(rvsdg::Region & region, fpsize size, const ::llvm::APFloat & constant)
541 {
543 }
544
548 [[nodiscard]] static ::llvm::APFloat
550 {
551 switch (size)
552 {
553 case fpsize::half:
554 return ::llvm::APFloat::getZero(::llvm::APFloat::IEEEhalf());
555 case fpsize::flt:
556 return ::llvm::APFloat::getZero(::llvm::APFloat::IEEEsingle());
557 case fpsize::dbl:
558 return ::llvm::APFloat::getZero(::llvm::APFloat::IEEEdouble());
559 case fpsize::x86fp80:
560 return ::llvm::APFloat::getZero(::llvm::APFloat::x87DoubleExtended());
561 case fpsize::fp128:
562 return ::llvm::APFloat::getZero(::llvm::APFloat::IEEEquad());
563 default:
564 JLM_UNREACHABLE("Unknown float size");
565 }
566 }
567
568private:
569 /* FIXME: I would not like to use the APFloat here,
570 but I don't have a replacement right now. */
571 ::llvm::APFloat constant_;
572};
573
574/* floating point comparison operator */
575
576enum class fpcmp
577{
578 TRUE,
579 FALSE,
580 oeq,
581 ogt,
582 oge,
583 olt,
584 ole,
585 one,
586 ord,
587 ueq,
588 ugt,
589 uge,
590 ult,
591 ule,
592 une,
593 uno
594};
595
597{
598public:
599 ~FCmpOperation() noexcept override;
600
607
608 FCmpOperation(const fpcmp & cmp, const std::shared_ptr<const FloatingPointType> & fpt)
610 cmp_(cmp)
611 {}
612
613 bool
614 operator==(const Operation & other) const noexcept override;
615
616 [[nodiscard]] std::string
617 debug_string() const override;
618
619 [[nodiscard]] std::unique_ptr<Operation>
620 copy() const override;
621
624 const noexcept override;
625
629 jlm::rvsdg::Output * op1,
630 jlm::rvsdg::Output * op2) const override;
631
632 inline const fpcmp &
633 cmp() const noexcept
634 {
635 return cmp_;
636 }
637
638 inline const fpsize &
639 size() const noexcept
640 {
641 return std::static_pointer_cast<const FloatingPointType>(argument(0))->size();
642 }
643
644 static std::unique_ptr<llvm::ThreeAddressCode>
645 create(const fpcmp & cmp, const Variable * op1, const Variable * op2)
646 {
647 auto ft = std::dynamic_pointer_cast<const FloatingPointType>(op1->Type());
648 if (!ft)
649 throw util::Error("expected floating point type.");
650
651 auto op = std::make_unique<FCmpOperation>(cmp, std::move(ft));
652 return ThreeAddressCode::create(std::move(op), { op1, op2 });
653 }
654
655private:
657};
658
664{
665public:
666 ~UndefValueOperation() noexcept override;
667
668 explicit UndefValueOperation(std::shared_ptr<const jlm::rvsdg::Type> type)
669 : SimpleOperation({}, { std::move(type) })
670 {}
671
673
676
679
680 bool
681 operator==(const Operation & other) const noexcept override;
682
683 [[nodiscard]] std::string
684 debug_string() const override;
685
686 [[nodiscard]] std::unique_ptr<Operation>
687 copy() const override;
688
689 [[nodiscard]] const rvsdg::Type &
690 GetType() const noexcept
691 {
692 return *result(0);
693 }
694
695 static jlm::rvsdg::Output *
696 Create(rvsdg::Region & region, std::shared_ptr<const jlm::rvsdg::Type> type)
697 {
698 return rvsdg::CreateOpNode<UndefValueOperation>(region, std::move(type)).output(0);
699 }
700
701 static std::unique_ptr<llvm::ThreeAddressCode>
702 Create(std::shared_ptr<const jlm::rvsdg::Type> type)
703 {
704 auto operation = std::make_unique<UndefValueOperation>(std::move(type));
705 return ThreeAddressCode::create(std::move(operation), {});
706 }
707
708 static std::unique_ptr<llvm::ThreeAddressCode>
709 Create(std::shared_ptr<const jlm::rvsdg::Type> type, const std::string & name)
710 {
711 auto operation = std::make_unique<UndefValueOperation>(std::move(type));
712 return ThreeAddressCode::create(std::move(operation), {}, { name });
713 }
714
715 static std::unique_ptr<llvm::ThreeAddressCode>
716 Create(std::unique_ptr<ThreeAddressCodeVariable> result)
717 {
718 auto & type = result->Type();
719
720 std::vector<std::unique_ptr<ThreeAddressCodeVariable>> results;
721 results.push_back(std::move(result));
722
723 auto operation = std::make_unique<UndefValueOperation>(type);
724 return ThreeAddressCode::create(std::move(operation), {}, std::move(results));
725 }
726};
727
733{
734public:
735 ~PoisonValueOperation() noexcept override;
736
737 explicit PoisonValueOperation(std::shared_ptr<const jlm::rvsdg::Type> type)
738 : SimpleOperation({}, { std::move(type) })
739 {}
740
742
744
747
750
751 bool
752 operator==(const Operation & other) const noexcept override;
753
754 std::string
755 debug_string() const override;
756
757 [[nodiscard]] std::unique_ptr<Operation>
758 copy() const override;
759
760 const jlm::rvsdg::Type &
761 GetType() const noexcept
762 {
763 return *result(0).get();
764 }
765
766 static std::unique_ptr<llvm::ThreeAddressCode>
767 Create(const std::shared_ptr<const jlm::rvsdg::Type> & type)
768 {
769 auto valueType = CheckAndConvertType(type);
770
771 auto operation = std::make_unique<PoisonValueOperation>(std::move(valueType));
772 return ThreeAddressCode::create(std::move(operation), {});
773 }
774
775 static jlm::rvsdg::Output *
776 Create(rvsdg::Region * region, const std::shared_ptr<const jlm::rvsdg::Type> & type)
777 {
778 auto valueType = CheckAndConvertType(type);
779
780 return rvsdg::CreateOpNode<PoisonValueOperation>(*region, std::move(valueType)).output(0);
781 }
782
783private:
784 static std::shared_ptr<const jlm::rvsdg::Type>
785 CheckAndConvertType(const std::shared_ptr<const jlm::rvsdg::Type> & type)
786 {
787 if (type->Kind() == rvsdg::TypeKind::Value)
788 return type;
789
790 throw util::Error("Expected value type.");
791 }
792};
793
801{
802public:
803 ~FreezeOperation() noexcept override;
804
805 explicit FreezeOperation(std::shared_ptr<const jlm::rvsdg::Type> type)
806 : rvsdg::UnaryOperation(type, type)
807 {
808 if (type->Kind() != rvsdg::TypeKind::Value)
809 throw std::runtime_error("FreezeOperation given non-value type");
810 }
811
812 bool
813 operator==(const Operation & other) const noexcept override;
814
815 std::string
816 debug_string() const override;
817
818 [[nodiscard]] std::unique_ptr<Operation>
819 copy() const override;
820
821 const jlm::rvsdg::Type &
822 getType() const noexcept
823 {
824 return *result(0).get();
825 }
826
827 static std::unique_ptr<llvm::ThreeAddressCode>
828 createTac(const Variable & operand)
829 {
830 auto operation = std::make_unique<FreezeOperation>(operand.Type());
831 return ThreeAddressCode::create(std::move(operation), { &operand });
832 }
833
834 static jlm::rvsdg::Node &
836 {
837 return rvsdg::CreateOpNode<FreezeOperation>({ &operand }, operand.Type());
838 }
839};
840
841/* floating point arithmetic operator */
842
843enum class fpop
844{
845 add,
846 sub,
847 mul,
848 div,
849 mod
850};
851
853{
854public:
855 ~FBinaryOperation() noexcept override;
856
863
864 FBinaryOperation(const llvm::fpop & op, const std::shared_ptr<const FloatingPointType> & fpt)
865 : BinaryOperation({ fpt, fpt }, fpt),
866 op_(op)
867 {}
868
869 bool
870 operator==(const Operation & other) const noexcept override;
871
872 [[nodiscard]] std::string
873 debug_string() const override;
874
875 [[nodiscard]] std::unique_ptr<Operation>
876 copy() const override;
877
880 const noexcept override;
881
885 jlm::rvsdg::Output * op1,
886 jlm::rvsdg::Output * op2) const override;
887
888 inline const llvm::fpop &
889 fpop() const noexcept
890 {
891 return op_;
892 }
893
894 inline const fpsize &
895 size() const noexcept
896 {
897 return std::static_pointer_cast<const FloatingPointType>(result(0))->size();
898 }
899
900 static std::unique_ptr<llvm::ThreeAddressCode>
901 create(const llvm::fpop & fpop, const Variable * op1, const Variable * op2)
902 {
903 auto ft = std::dynamic_pointer_cast<const FloatingPointType>(op1->Type());
904 if (!ft)
905 throw util::Error("expected floating point type.");
906
907 auto op = std::make_unique<FBinaryOperation>(fpop, ft);
908 return ThreeAddressCode::create(std::move(op), { op1, op2 });
909 }
910
911private:
913};
914
916{
917public:
918 ~FNegOperation() noexcept override;
919
920 explicit FNegOperation(const fpsize & size)
922 {}
923
924 explicit FNegOperation(const std::shared_ptr<const FloatingPointType> & fpt)
925 : UnaryOperation(fpt, fpt)
926 {}
927
928 bool
929 operator==(const Operation & other) const noexcept override;
930
931 [[nodiscard]] std::string
932 debug_string() const override;
933
934 [[nodiscard]] std::unique_ptr<Operation>
935 copy() const override;
936
937 const fpsize &
938 size() const noexcept
939 {
940 return std::static_pointer_cast<const FloatingPointType>(argument(0))->size();
941 }
942
943 static std::unique_ptr<llvm::ThreeAddressCode>
944 create(const Variable * operand)
945 {
946 auto type = std::dynamic_pointer_cast<const FloatingPointType>(operand->Type());
947 if (!type)
948 throw util::Error("expected floating point type.");
949
950 auto op = std::make_unique<FNegOperation>(std::move(type));
951 return ThreeAddressCode::create(std::move(op), { operand });
952 }
953};
954
956{
957public:
959
960 explicit VariadicArgumentListOperation(std::vector<std::shared_ptr<const jlm::rvsdg::Type>> types)
961 : SimpleOperation(std::move(types), { VariableArgumentType::Create() })
962 {}
963
965
968
971
972 bool
973 operator==(const Operation & other) const noexcept override;
974
975 [[nodiscard]] std::string
976 debug_string() const override;
977
978 [[nodiscard]] std::unique_ptr<Operation>
979 copy() const override;
980
981 static std::unique_ptr<llvm::ThreeAddressCode>
982 create(const std::vector<const Variable *> & arguments)
983 {
984 std::vector<std::shared_ptr<const jlm::rvsdg::Type>> operands;
985 for (const auto & argument : arguments)
986 operands.push_back(argument->Type());
987
988 auto op = std::make_unique<VariadicArgumentListOperation>(std::move(operands));
989 return ThreeAddressCode::create(std::move(op), arguments);
990 }
991
992 static rvsdg::Output *
993 Create(rvsdg::Region & region, const std::vector<rvsdg::Output *> & operands)
994 {
995 std::vector<std::shared_ptr<const rvsdg::Type>> operandTypes;
996 operandTypes.reserve(operands.size());
997 for (auto & operand : operands)
998 operandTypes.emplace_back(operand->Type());
999
1000 return operands.empty()
1001 ? rvsdg::CreateOpNode<VariadicArgumentListOperation>(region, std::move(operandTypes))
1002 .output(0)
1003 : rvsdg::CreateOpNode<VariadicArgumentListOperation>(operands, std::move(operandTypes))
1004 .output(0);
1005 }
1006};
1007
1009{
1010public:
1011 ~ConstantStructOperation() noexcept override;
1012
1013 explicit ConstantStructOperation(std::shared_ptr<const StructType> type)
1015 {}
1016
1017 bool
1018 operator==(const Operation & other) const noexcept override;
1019
1020 [[nodiscard]] std::string
1021 debug_string() const override;
1022
1023 [[nodiscard]] std::unique_ptr<Operation>
1024 copy() const override;
1025
1026 const StructType &
1027 type() const noexcept
1028 {
1029 return *std::static_pointer_cast<const StructType>(result(0));
1030 }
1031
1032 static std::unique_ptr<ThreeAddressCode>
1034 const std::vector<const Variable *> & elements,
1035 const std::shared_ptr<const rvsdg::Type> & type)
1036 {
1037 auto structType = CheckAndExtractStructType(type);
1038
1039 auto op = std::make_unique<ConstantStructOperation>(std::move(structType));
1040 return ThreeAddressCode::create(std::move(op), elements);
1041 }
1042
1043 static rvsdg::Output &
1045 rvsdg::Region &,
1046 const std::vector<rvsdg::Output *> & operands,
1047 std::shared_ptr<const rvsdg::Type> resultType)
1048 {
1049 auto structType = CheckAndExtractStructType(std::move(resultType));
1050 return *rvsdg::CreateOpNode<ConstantStructOperation>(operands, std::move(structType)).output(0);
1051 }
1052
1053private:
1054 static std::vector<std::shared_ptr<const rvsdg::Type>>
1056 {
1057 std::vector<std::shared_ptr<const rvsdg::Type>> types;
1058 for (size_t n = 0; n < type.numElements(); n++)
1059 types.push_back(type.getElementType(n));
1060
1061 return types;
1062 }
1063
1064 static std::shared_ptr<const StructType>
1065 CheckAndExtractStructType(std::shared_ptr<const rvsdg::Type> type)
1066 {
1067 if (auto structType = std::dynamic_pointer_cast<const StructType>(type))
1068 {
1069 return structType;
1070 }
1071
1072 throw util::TypeError("StructType", type->debug_string());
1073 }
1074};
1075
1077{
1078public:
1079 ~ConstantArrayOperation() noexcept override;
1080
1081 ConstantArrayOperation(const std::shared_ptr<const jlm::rvsdg::Type> & type, size_t size)
1083 {
1084 if (size == 0)
1085 throw util::Error("size equals zero.\n");
1086 }
1087
1088 bool
1089 operator==(const Operation & other) const noexcept override;
1090
1091 [[nodiscard]] std::string
1092 debug_string() const override;
1093
1094 [[nodiscard]] std::unique_ptr<Operation>
1095 copy() const override;
1096
1097 size_t
1098 size() const noexcept
1099 {
1100 return std::static_pointer_cast<const ArrayType>(result(0))->nelements();
1101 }
1102
1103 [[nodiscard]] std::shared_ptr<const ArrayType>
1104 type() const noexcept
1105 {
1106 JLM_ASSERT(std::dynamic_pointer_cast<const ArrayType>(result(0)));
1107 return std::static_pointer_cast<const ArrayType>(result(0));
1108 }
1109
1110 static std::unique_ptr<llvm::ThreeAddressCode>
1111 create(const std::vector<const Variable *> & elements)
1112 {
1113 if (elements.size() == 0)
1114 throw util::Error("expected at least one element.\n");
1115
1116 auto vt = elements[0]->Type();
1117 if (vt->Kind() != rvsdg::TypeKind::Value)
1118 throw util::Error("expected value Type.\n");
1119
1120 auto op = std::make_unique<ConstantArrayOperation>(vt, elements.size());
1121 return ThreeAddressCode::create(std::move(op), elements);
1122 }
1123
1124 static rvsdg::Output *
1125 Create(const std::vector<rvsdg::Output *> & operands)
1126 {
1127 if (operands.empty())
1128 throw util::Error("Expected at least one element.\n");
1129
1130 auto valueType = operands[0]->Type();
1131 if (valueType->Kind() != rvsdg::TypeKind::Value)
1132 {
1133 throw util::Error("Expected value type.\n");
1134 }
1135
1136 return rvsdg::CreateOpNode<ConstantArrayOperation>(operands, valueType, operands.size())
1137 .output(0);
1138 }
1139};
1140
1142{
1143public:
1145
1146 explicit ConstantAggregateZeroOperation(std::shared_ptr<const rvsdg::Type> type)
1147 : SimpleOperation({}, { type })
1148 {
1149 auto st = dynamic_cast<const StructType *>(type.get());
1150 auto at = dynamic_cast<const ArrayType *>(type.get());
1151 auto vt = dynamic_cast<const VectorType *>(type.get());
1152 if (!st && !at && !vt)
1153 throw util::Error("expected array, struct, or vector type.\n");
1154 }
1155
1156 bool
1157 operator==(const Operation & other) const noexcept override;
1158
1159 [[nodiscard]] std::string
1160 debug_string() const override;
1161
1162 [[nodiscard]] std::unique_ptr<Operation>
1163 copy() const override;
1164
1165 static std::unique_ptr<llvm::ThreeAddressCode>
1166 create(std::shared_ptr<const jlm::rvsdg::Type> type)
1167 {
1168 auto op = std::make_unique<ConstantAggregateZeroOperation>(std::move(type));
1169 return ThreeAddressCode::create(std::move(op), {});
1170 }
1171
1172 static rvsdg::SimpleNode &
1173 createNode(rvsdg::Region & region, std::shared_ptr<const rvsdg::Type> type)
1174 {
1175 return rvsdg::CreateOpNode<ConstantAggregateZeroOperation>(region, std::move(type));
1176 }
1177
1178 static rvsdg::Output *
1179 Create(rvsdg::Region & region, const std::shared_ptr<const rvsdg::Type> & type)
1180 {
1181 return createNode(region, type).output(0);
1182 }
1183};
1184
1186{
1187public:
1188 ~ExtractElementOperation() noexcept override;
1189
1191 const std::shared_ptr<const VectorType> & vtype,
1192 const std::shared_ptr<const jlm::rvsdg::BitType> & btype)
1193 : SimpleOperation({ vtype, btype }, { vtype->Type() })
1194 {}
1195
1196 bool
1197 operator==(const Operation & other) const noexcept override;
1198
1199 [[nodiscard]] std::string
1200 debug_string() const override;
1201
1202 [[nodiscard]] std::unique_ptr<Operation>
1203 copy() const override;
1204
1205 static inline std::unique_ptr<llvm::ThreeAddressCode>
1206 create(const llvm::Variable * vector, const llvm::Variable * index)
1207 {
1208 auto vt = std::dynamic_pointer_cast<const VectorType>(vector->Type());
1209 if (!vt)
1210 throw util::Error("expected vector type.");
1211
1212 auto bt = std::dynamic_pointer_cast<const jlm::rvsdg::BitType>(index->Type());
1213 if (!bt)
1214 throw util::Error("expected bit type.");
1215
1216 auto op = std::make_unique<ExtractElementOperation>(vt, bt);
1217 return ThreeAddressCode::create(std::move(op), { vector, index });
1218 }
1219};
1220
1222{
1223public:
1224 ~ShuffleVectorOperation() noexcept override;
1225
1227 const std::shared_ptr<const FixedVectorType> & v,
1228 const std::vector<int> & mask)
1229 : SimpleOperation({ v, v }, { v }),
1230 Mask_(mask)
1231 {}
1232
1234 const std::shared_ptr<const ScalableVectorType> & v,
1235 const std::vector<int> & mask)
1236 : SimpleOperation({ v, v }, { v }),
1237 Mask_(mask)
1238 {}
1239
1240 bool
1241 operator==(const Operation & other) const noexcept override;
1242
1243 [[nodiscard]] std::string
1244 debug_string() const override;
1245
1246 [[nodiscard]] std::unique_ptr<Operation>
1247 copy() const override;
1248
1249 const ::llvm::ArrayRef<int>
1250 Mask() const
1251 {
1252 return Mask_;
1253 }
1254
1255 static std::unique_ptr<llvm::ThreeAddressCode>
1256 create(const Variable * v1, const Variable * v2, const std::vector<int> & mask)
1257 {
1258 if (is<FixedVectorType>(v1->type()) && is<FixedVectorType>(v2->type()))
1259 return CreateShuffleVectorTac<FixedVectorType>(v1, v2, mask);
1260
1261 if (is<ScalableVectorType>(v1->type()) && is<ScalableVectorType>(v2->type()))
1262 return CreateShuffleVectorTac<ScalableVectorType>(v1, v2, mask);
1263
1264 throw util::Error("Expected vector types as operands.");
1265 }
1266
1267private:
1268 template<typename T>
1269 static std::unique_ptr<ThreeAddressCode>
1270 CreateShuffleVectorTac(const Variable * v1, const Variable * v2, const std::vector<int> & mask)
1271 {
1272 auto vt = std::static_pointer_cast<const T>(v1->Type());
1273 auto op = std::make_unique<ShuffleVectorOperation>(vt, mask);
1274 return ThreeAddressCode::create(std::move(op), { v1, v2 });
1275 }
1276
1277 std::vector<int> Mask_;
1278};
1279
1281{
1282public:
1283 ~ConstantVectorOperation() noexcept override;
1284
1285 explicit ConstantVectorOperation(const std::shared_ptr<const VectorType> & vt)
1286 : SimpleOperation({ vt->size(), vt->Type() }, { vt })
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 static inline std::unique_ptr<llvm::ThreeAddressCode>
1300 const std::vector<const Variable *> & operands,
1301 const std::shared_ptr<const jlm::rvsdg::Type> & type)
1302 {
1303 auto vt = std::dynamic_pointer_cast<const VectorType>(type);
1304 if (!vt)
1305 throw util::Error("expected vector type.");
1306
1307 auto op = std::make_unique<ConstantVectorOperation>(vt);
1308 return ThreeAddressCode::create(std::move(op), operands);
1309 }
1310};
1311
1313{
1314public:
1315 ~InsertElementOperation() noexcept override;
1316
1318 const std::shared_ptr<const VectorType> & vectype,
1319 const std::shared_ptr<const jlm::rvsdg::Type> & vtype,
1320 const std::shared_ptr<const jlm::rvsdg::BitType> & btype)
1321 : SimpleOperation({ vectype, vtype, btype }, { vectype })
1322 {
1323 if (vectype->type() != *vtype)
1324 {
1325 auto received = vtype->debug_string();
1326 auto expected = vectype->type().debug_string();
1327 throw util::Error(jlm::util::strfmt("expected ", expected, ", got ", received));
1328 }
1329 }
1330
1331 bool
1332 operator==(const Operation & other) const noexcept override;
1333
1334 [[nodiscard]] std::string
1335 debug_string() const override;
1336
1337 [[nodiscard]] std::unique_ptr<Operation>
1338 copy() const override;
1339
1340 static inline std::unique_ptr<llvm::ThreeAddressCode>
1341 create(const llvm::Variable * vector, const llvm::Variable * value, const llvm::Variable * index)
1342 {
1343 auto vct = std::dynamic_pointer_cast<const VectorType>(vector->Type());
1344 if (!vct)
1345 throw util::Error("expected vector type.");
1346
1347 auto vt = value->Type();
1348 if (vt->Kind() != rvsdg::TypeKind::Value)
1349 throw util::Error("expected value type.");
1350
1351 auto bt = std::dynamic_pointer_cast<const jlm::rvsdg::BitType>(index->Type());
1352 if (!bt)
1353 throw util::Error("expected bit type.");
1354
1355 auto op = std::make_unique<InsertElementOperation>(vct, vt, bt);
1356 return ThreeAddressCode::create(std::move(op), { vector, value, index });
1357 }
1358};
1359
1361{
1362public:
1363 ~VectorUnaryOperation() noexcept override;
1364
1366 const rvsdg::UnaryOperation & op,
1367 const std::shared_ptr<const VectorType> & operand,
1368 const std::shared_ptr<const VectorType> & result)
1369 : SimpleOperation({ operand }, { result }),
1370 op_(op.copy())
1371 {
1372 // Bit casts can convert between vectors of different length, or between scalars and vectors,
1373 // so it should not be seen as a vector operation performed lane-wise.
1374 JLM_ASSERT(!is<BitCastOperation>(op));
1375
1376 if (operand->type() != *op.argument(0))
1377 {
1378 auto received = operand->type().debug_string();
1379 auto expected = op.argument(0)->debug_string();
1380 throw util::Error(jlm::util::strfmt("expected ", expected, ", got ", received));
1381 }
1382
1383 if (result->type() != *op.result(0))
1384 {
1385 auto received = result->type().debug_string();
1386 auto expected = op.result(0)->debug_string();
1387 throw util::Error(jlm::util::strfmt("expected ", expected, ", got ", received));
1388 }
1389 }
1390
1392 : SimpleOperation(other),
1393 op_(other.op_->copy())
1394 {}
1395
1397 : SimpleOperation(other),
1398 op_(std::move(other.op_))
1399 {}
1400
1403 {
1404 if (this != &other)
1405 op_ = other.op_->copy();
1406
1407 return *this;
1408 }
1409
1412 {
1413 if (this != &other)
1414 op_ = std::move(other.op_);
1415
1416 return *this;
1417 }
1418
1419 const rvsdg::UnaryOperation &
1420 operation() const noexcept
1421 {
1422 return *static_cast<const rvsdg::UnaryOperation *>(op_.get());
1423 }
1424
1425 bool
1426 operator==(const Operation & other) const noexcept override;
1427
1428 [[nodiscard]] std::string
1429 debug_string() const override;
1430
1431 [[nodiscard]] std::unique_ptr<Operation>
1432 copy() const override;
1433
1434 static inline std::unique_ptr<llvm::ThreeAddressCode>
1436 const rvsdg::UnaryOperation & unop,
1437 const llvm::Variable * operand,
1438 const std::shared_ptr<const jlm::rvsdg::Type> & type)
1439 {
1440 auto vct1 = std::dynamic_pointer_cast<const VectorType>(operand->Type());
1441 auto vct2 = std::dynamic_pointer_cast<const VectorType>(type);
1442 if (!vct1 || !vct2)
1443 throw util::Error("expected vector type.");
1444
1445 auto op = std::make_unique<VectorUnaryOperation>(unop, vct1, vct2);
1446 return ThreeAddressCode::create(std::move(op), { operand });
1447 }
1448
1449private:
1450 std::unique_ptr<Operation> op_;
1451};
1452
1454{
1455public:
1456 ~VectorBinaryOperation() noexcept override;
1457
1459 const rvsdg::BinaryOperation & binop,
1460 const std::shared_ptr<const VectorType> & op1,
1461 const std::shared_ptr<const VectorType> & op2,
1462 const std::shared_ptr<const VectorType> & result)
1463 : SimpleOperation({ op1, op2 }, { result }),
1464 op_(binop.copy())
1465 {
1466 if (*op1 != *op2)
1467 throw util::Error("expected the same vector types.");
1468
1469 if (op1->type() != *binop.argument(0))
1470 {
1471 auto received = op1->type().debug_string();
1472 auto expected = binop.argument(0)->debug_string();
1473 throw util::Error(jlm::util::strfmt("expected ", expected, ", got ", received));
1474 }
1475
1476 if (result->type() != *binop.result(0))
1477 {
1478 auto received = result->type().debug_string();
1479 auto expected = binop.result(0)->debug_string();
1480 throw util::Error(jlm::util::strfmt("expected ", expected, ", got ", received));
1481 }
1482 }
1483
1485 : SimpleOperation(other),
1486 op_(other.op_->copy())
1487 {}
1488
1490 : SimpleOperation(other),
1491 op_(std::move(other.op_))
1492 {}
1493
1496 {
1497 if (this != &other)
1498 op_ = other.op_->copy();
1499
1500 return *this;
1501 }
1502
1505 {
1506 if (this != &other)
1507 op_ = std::move(other.op_);
1508
1509 return *this;
1510 }
1511
1513 operation() const noexcept
1514 {
1515 return *static_cast<const rvsdg::BinaryOperation *>(op_.get());
1516 }
1517
1518 bool
1519 operator==(const Operation & other) const noexcept override;
1520
1521 [[nodiscard]] std::string
1522 debug_string() const override;
1523
1524 [[nodiscard]] std::unique_ptr<Operation>
1525 copy() const override;
1526
1527 static inline std::unique_ptr<llvm::ThreeAddressCode>
1529 const rvsdg::BinaryOperation & binop,
1530 const llvm::Variable * op1,
1531 const llvm::Variable * op2,
1532 const std::shared_ptr<const jlm::rvsdg::Type> & type)
1533 {
1534 auto vct1 = std::dynamic_pointer_cast<const VectorType>(op1->Type());
1535 auto vct2 = std::dynamic_pointer_cast<const VectorType>(op2->Type());
1536 auto vct3 = std::dynamic_pointer_cast<const VectorType>(type);
1537 if (!vct1 || !vct2 || !vct3)
1538 throw util::Error("expected vector type.");
1539
1540 auto op = std::make_unique<VectorBinaryOperation>(binop, vct1, vct2, vct3);
1541 return ThreeAddressCode::create(std::move(op), { op1, op2 });
1542 }
1543
1544private:
1545 std::unique_ptr<Operation> op_;
1546};
1547
1549{
1550public:
1551 ~ConstantDataVectorOperation() noexcept override;
1552
1553private:
1554 explicit ConstantDataVectorOperation(const std::shared_ptr<const VectorType> & vt)
1555 : SimpleOperation({ vt->size(), vt->Type() }, { vt })
1556 {}
1557
1558public:
1559 bool
1560 operator==(const Operation & other) const noexcept override;
1561
1562 [[nodiscard]] std::string
1563 debug_string() const override;
1564
1565 [[nodiscard]] std::unique_ptr<Operation>
1566 copy() const override;
1567
1568 size_t
1569 size() const noexcept
1570 {
1571 return std::static_pointer_cast<const VectorType>(result(0))->size();
1572 }
1573
1574 const jlm::rvsdg::Type &
1575 type() const noexcept
1576 {
1577 return std::static_pointer_cast<const VectorType>(result(0))->type();
1578 }
1579
1580 static std::unique_ptr<ThreeAddressCode>
1581 Create(const std::vector<const Variable *> & elements)
1582 {
1583 if (elements.empty())
1584 throw util::Error("Expected at least one element.");
1585
1586 auto vt = elements[0]->Type();
1587 if (vt->Kind() != rvsdg::TypeKind::Value)
1588 throw util::Error("Expected value type.");
1589
1590 auto op = std::unique_ptr<ConstantDataVectorOperation>(
1592 return ThreeAddressCode::create(std::move(op), elements);
1593 }
1594};
1595
1602{
1603public:
1604 ~MallocOperation() noexcept override;
1605
1606 explicit MallocOperation(std::shared_ptr<const rvsdg::BitType> type)
1608 { std::move(type), IOStateType::Create() },
1610 {}
1611
1612 bool
1613 operator==(const Operation & other) const noexcept override;
1614
1615 [[nodiscard]] std::string
1616 debug_string() const override;
1617
1618 [[nodiscard]] std::unique_ptr<Operation>
1619 copy() const override;
1620
1621 const rvsdg::BitType &
1622 getSizeType() const noexcept
1623 {
1624 return *std::static_pointer_cast<const rvsdg::BitType>(argument(0));
1625 }
1626
1629 {
1630 JLM_ASSERT(narguments() == 2 && nresults() == 3);
1631 return rvsdg::FunctionType({ argument(0), argument(1) }, { result(0), result(1), result(2) });
1632 }
1633
1634 static rvsdg::Input &
1636 {
1637 JLM_ASSERT(is<MallocOperation>(node.GetOperation()));
1638 auto & size = *node.input(0);
1639 JLM_ASSERT(is<rvsdg::BitType>(size.Type()));
1640 return size;
1641 }
1642
1643 static rvsdg::Input &
1645 {
1646 JLM_ASSERT(is<MallocOperation>(node.GetOperation()));
1647 auto & ioState = *node.input(1);
1648 JLM_ASSERT(is<IOStateType>(ioState.Type()));
1649 return ioState;
1650 }
1651
1652 static rvsdg::Output &
1654 {
1655 JLM_ASSERT(is<MallocOperation>(node.GetOperation()));
1656 auto & address = *node.output(0);
1657 JLM_ASSERT(is<PointerType>(address.Type()));
1658 return address;
1659 }
1660
1661 static rvsdg::Output &
1663 {
1664 JLM_ASSERT(is<MallocOperation>(node.GetOperation()));
1665 auto & ioState = *node.output(1);
1666 JLM_ASSERT(is<IOStateType>(ioState.Type()));
1667 return ioState;
1668 }
1669
1670 static rvsdg::Output &
1672 {
1673 JLM_ASSERT(is<MallocOperation>(node.GetOperation()));
1674 auto & memoryState = *node.output(2);
1675 JLM_ASSERT(is<MemoryStateType>(memoryState.Type()));
1676 return memoryState;
1677 }
1678
1679 static std::unique_ptr<ThreeAddressCode>
1680 createTac(const Variable * size, const Variable * ioState)
1681 {
1682 auto bitType = checkAndExtractSizeType(size->Type());
1683 auto op = std::make_unique<MallocOperation>(std::move(bitType));
1684 return ThreeAddressCode::create(std::move(op), { size, ioState });
1685 }
1686
1687 static rvsdg::SimpleNode &
1689 {
1690 auto bitType = checkAndExtractSizeType(size.Type());
1691 return rvsdg::CreateOpNode<MallocOperation>({ &size, &ioState }, std::move(bitType));
1692 }
1693
1694private:
1695 static std::shared_ptr<const rvsdg::BitType>
1696 checkAndExtractSizeType(const std::shared_ptr<const rvsdg::Type> & type)
1697 {
1698 if (auto bitType = std::dynamic_pointer_cast<const rvsdg::BitType>(type))
1699 return bitType;
1700
1701 throw std::runtime_error("Expected bits type.");
1702 }
1703};
1704
1711{
1712public:
1713 ~FreeOperation() noexcept override;
1714
1715 explicit FreeOperation(size_t numMemoryStates)
1716 : SimpleOperation(CreateOperandTypes(numMemoryStates), CreateResultTypes(numMemoryStates))
1717 {}
1718
1719 bool
1720 operator==(const Operation & other) const noexcept override;
1721
1722 [[nodiscard]] std::string
1723 debug_string() const override;
1724
1725 [[nodiscard]] std::unique_ptr<Operation>
1726 copy() const override;
1727
1732 [[nodiscard]] static rvsdg::Input &
1733 addressInput(const rvsdg::Node & node) noexcept
1734 {
1735 JLM_ASSERT(is<FreeOperation>(&node));
1736 const auto input = node.input(0);
1737 JLM_ASSERT(is<PointerType>(input->Type()));
1738 return *input;
1739 }
1740
1741 [[nodiscard]] static rvsdg::Input &
1743 {
1744 JLM_ASSERT(is<MemoryStateType>(output.Type()));
1745 auto [freeNode, freeOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<FreeOperation>(output);
1746 JLM_ASSERT(freeOperation);
1747 const auto input = freeNode->input(output.index() + 1);
1748 JLM_ASSERT(is<MemoryStateType>(input->Type()));
1749 return *input;
1750 }
1751
1752 static std::unique_ptr<llvm::ThreeAddressCode>
1754 const Variable * pointer,
1755 const std::vector<const Variable *> & memoryStates,
1756 const Variable * iOState)
1757 {
1758 std::vector<const Variable *> operands;
1759 operands.push_back(pointer);
1760 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
1761 operands.push_back(iOState);
1762
1763 auto operation = std::make_unique<FreeOperation>(memoryStates.size());
1764 return ThreeAddressCode::create(std::move(operation), operands);
1765 }
1766
1767 static std::vector<jlm::rvsdg::Output *>
1769 jlm::rvsdg::Output * pointer,
1770 const std::vector<jlm::rvsdg::Output *> & memoryStates,
1771 jlm::rvsdg::Output * iOState)
1772 {
1773 std::vector<jlm::rvsdg::Output *> operands;
1774 operands.push_back(pointer);
1775 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
1776 operands.push_back(iOState);
1777
1778 return outputs(&rvsdg::CreateOpNode<FreeOperation>(operands, memoryStates.size()));
1779 }
1780
1781private:
1782 static std::vector<std::shared_ptr<const rvsdg::Type>>
1783 CreateOperandTypes(size_t numMemoryStates)
1784 {
1785 std::vector<std::shared_ptr<const rvsdg::Type>> memoryStates(
1786 numMemoryStates,
1788
1789 std::vector<std::shared_ptr<const rvsdg::Type>> types({ PointerType::Create() });
1790 types.insert(types.end(), memoryStates.begin(), memoryStates.end());
1791 types.emplace_back(IOStateType::Create());
1792
1793 return types;
1794 }
1795
1796 static std::vector<std::shared_ptr<const rvsdg::Type>>
1797 CreateResultTypes(size_t numMemoryStates)
1798 {
1799 std::vector<std::shared_ptr<const rvsdg::Type>> types(
1800 numMemoryStates,
1802 types.emplace_back(IOStateType::Create());
1803
1804 return types;
1805 }
1806};
1807}
1808
1809#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:68
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:62
AssignmentOperation(const AssignmentOperation &)=default
AssignmentOperation(AssignmentOperation &&)=default
bool operator==(const Operation &other) const noexcept override
Definition operators.cpp:55
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)
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
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 std::vector< std::shared_ptr< const rvsdg::Type > > CreateResultTypes(size_t numMemoryStates)
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateOperandTypes(size_t numMemoryStates)
static rvsdg::Input & mapMemoryStateOutputToInput(rvsdg::Output &output) noexcept
bool operator==(const Operation &other) const noexcept override
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *pointer, const std::vector< const Variable * > &memoryStates, const Variable *iOState)
~FreeOperation() noexcept override
static rvsdg::Input & addressInput(const rvsdg::Node &node) noexcept
static std::vector< jlm::rvsdg::Output * > Create(jlm::rvsdg::Output *pointer, const std::vector< jlm::rvsdg::Output * > &memoryStates, jlm::rvsdg::Output *iOState)
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)
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:76
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:83
std::unique_ptr< Operation > copy() const override
Definition operators.cpp:89
~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:32
bool operator==(const Operation &other) const noexcept override
Definition operators.cpp:25
std::unique_ptr< Operation > copy() const override
Definition operators.cpp:47
~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:135
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:97
~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