Jlm
Loading...
Searching...
No Matches
StdLibIntrinsicOperations.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2024 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#ifndef JLM_LLVM_IR_OPERATORS_STDLIBINTRINSICOPERATIONS_HPP
7#define JLM_LLVM_IR_OPERATORS_STDLIBINTRINSICOPERATIONS_HPP
8
9#include <jlm/llvm/ir/tac.hpp>
10#include <jlm/llvm/ir/types.hpp>
13
14namespace jlm::llvm
15{
16
24{
25protected:
27 const std::vector<std::shared_ptr<const rvsdg::Type>> & operandTypes,
28 const std::vector<std::shared_ptr<const rvsdg::Type>> & resultTypes)
29 : SimpleOperation(operandTypes, resultTypes)
30 {
31 JLM_ASSERT(operandTypes.size() >= 3);
32
33 auto & dstAddressType = *operandTypes[0];
34 JLM_ASSERT(is<PointerType>(dstAddressType));
35
36 auto & srcAddressType = *operandTypes[1];
37 JLM_ASSERT(is<PointerType>(srcAddressType));
38
39 auto & lengthType = *operandTypes[2];
40 if (lengthType != *rvsdg::BitType::Create(32) && lengthType != *rvsdg::BitType::Create(64))
41 {
42 throw util::Error("Expected 32 bit or 64 bit integer type.");
43 }
44 }
45
46public:
47 [[nodiscard]] const rvsdg::BitType &
48 LengthType() const noexcept
49 {
50 auto type = std::dynamic_pointer_cast<const rvsdg::BitType>(argument(2));
51 JLM_ASSERT(type != nullptr);
52 return *type;
53 }
54
55 [[nodiscard]] virtual size_t
56 NumMemoryStates() const noexcept = 0;
57
62 [[nodiscard]] static rvsdg::Input &
63 destinationInput(const rvsdg::Node & node) noexcept
64 {
65 JLM_ASSERT(is<MemCpyOperation>(&node));
66 const auto input = node.input(0);
67 JLM_ASSERT(is<PointerType>(input->Type()));
68 return *input;
69 }
70
75 [[nodiscard]] static rvsdg::Input &
76 sourceInput(const rvsdg::Node & node) noexcept
77 {
78 JLM_ASSERT(is<MemCpyOperation>(&node));
79 const auto input = node.input(1);
80 JLM_ASSERT(is<PointerType>(input->Type()));
81 return *input;
82 }
83
88 [[nodiscard]] static rvsdg::Input &
89 countInput(const rvsdg::Node & node) noexcept
90 {
91 JLM_ASSERT(is<MemCpyOperation>(&node));
92 const auto input = node.input(2);
93 JLM_ASSERT(is<rvsdg::BitType>(input->Type()));
94 return *input;
95 }
96
100 [[nodiscard]] static rvsdg::Input &
102 {
103 JLM_ASSERT(is<MemoryStateType>(output.Type()));
104 auto [memCpyNode, memCpyOperation] =
106 JLM_ASSERT(memCpyOperation);
107 const auto numNonMemoryStateOutputs =
108 memCpyNode->noutputs() - memCpyOperation->NumMemoryStates();
109 JLM_ASSERT(output.index() >= numNonMemoryStateOutputs);
110 const auto numNonMemoryStateInputs = memCpyNode->ninputs() - memCpyOperation->NumMemoryStates();
111 const auto inputIndex = numNonMemoryStateInputs + (output.index() - numNonMemoryStateOutputs);
112 const auto input = memCpyNode->input(inputIndex);
113 JLM_ASSERT(is<MemoryStateType>(input->Type()));
114 return *input;
115 }
116
120 [[nodiscard]] static rvsdg::Output &
122 {
123 JLM_ASSERT(is<MemoryStateType>(input.Type()));
124 auto [memCpyNode, memCpyOperation] =
126 JLM_ASSERT(memCpyOperation);
127 const auto numNonMemoryStateInputs = memCpyNode->ninputs() - memCpyOperation->NumMemoryStates();
128 JLM_ASSERT(input.index() >= numNonMemoryStateInputs);
129 const auto numNonMemoryStateOutputs =
130 memCpyNode->noutputs() - memCpyOperation->NumMemoryStates();
131 const auto outputIndex = numNonMemoryStateOutputs + (input.index() - numNonMemoryStateInputs);
132 const auto output = memCpyNode->output(outputIndex);
133 JLM_ASSERT(is<MemoryStateType>(output->Type()));
134 return *output;
135 }
136};
137
144{
145public:
147
148 MemCpyNonVolatileOperation(std::shared_ptr<const rvsdg::Type> lengthType, size_t numMemoryStates)
150 CreateOperandTypes(std::move(lengthType), numMemoryStates),
151 CreateResultTypes(numMemoryStates))
152 {}
153
154 bool
155 operator==(const Operation & other) const noexcept override;
156
157 [[nodiscard]] std::string
158 debug_string() const override;
159
160 [[nodiscard]] std::unique_ptr<Operation>
161 copy() const override;
162
163 [[nodiscard]] size_t
164 NumMemoryStates() const noexcept override;
165
166 static std::unique_ptr<llvm::ThreeAddressCode>
168 const Variable * destination,
169 const Variable * source,
170 const Variable * length,
171 const std::vector<const Variable *> & memoryStates)
172 {
173 std::vector<const Variable *> operands = { destination, source, length };
174 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
175
176 auto operation =
177 std::make_unique<MemCpyNonVolatileOperation>(length->Type(), memoryStates.size());
178 return ThreeAddressCode::create(std::move(operation), operands);
179 }
180
181 static rvsdg::SimpleNode &
183 rvsdg::Output & destination,
184 rvsdg::Output & source,
185 rvsdg::Output & length,
186 const std::vector<rvsdg::Output *> & memoryStates)
187 {
188 std::vector operands = { &destination, &source, &length };
189 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
190
192 operands,
193 length.Type(),
194 memoryStates.size());
195 }
196
197 static std::vector<rvsdg::Output *>
199 rvsdg::Output * destination,
200 rvsdg::Output * source,
201 rvsdg::Output * length,
202 const std::vector<rvsdg::Output *> & memoryStates)
203 {
204 std::vector operands = { destination, source, length };
205 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
206
208 operands,
209 length->Type(),
210 memoryStates.size()));
211 }
212
213private:
214 static std::vector<std::shared_ptr<const rvsdg::Type>>
215 CreateOperandTypes(std::shared_ptr<const rvsdg::Type> length, size_t numMemoryStates)
216 {
217 auto pointerType = PointerType::Create();
218 std::vector<std::shared_ptr<const rvsdg::Type>> types = { pointerType, pointerType, length };
219 types.insert(types.end(), numMemoryStates, MemoryStateType::Create());
220 return types;
221 }
222
223 static std::vector<std::shared_ptr<const rvsdg::Type>>
224 CreateResultTypes(size_t numMemoryStates)
225 {
226 // The memcpy() standard C library call has as return type void*, but LLVM models the
227 // function call nevertheless as:
228 // call void @llvm.memcpy.p0.p0.i64(ptr align 4 %7, ptr align 4 %8, i64 %9, i1 false)
229 //
230 // LLVM simply hands in register %7 (dest pointer) to all users of the return type of memcpy().
231 // Thus, we only need state types as result types of the operation here.
232 return { numMemoryStates, MemoryStateType::Create() };
233 }
234};
235
248{
249public:
250 ~MemCpyVolatileOperation() noexcept override;
251
252 MemCpyVolatileOperation(std::shared_ptr<const rvsdg::Type> lengthType, size_t numMemoryStates)
254 CreateOperandTypes(std::move(lengthType), numMemoryStates),
255 CreateResultTypes(numMemoryStates))
256 {}
257
258 bool
259 operator==(const Operation & other) const noexcept override;
260
261 [[nodiscard]] std::string
262 debug_string() const override;
263
264 [[nodiscard]] std::unique_ptr<Operation>
265 copy() const override;
266
267 [[nodiscard]] size_t
268 NumMemoryStates() const noexcept override;
269
270 static std::unique_ptr<llvm::ThreeAddressCode>
272 const Variable & destination,
273 const Variable & source,
274 const Variable & length,
275 const Variable & ioState,
276 const std::vector<const Variable *> & memoryStates)
277 {
278 std::vector<const Variable *> operands = { &destination, &source, &length, &ioState };
279 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
280
281 auto operation = std::make_unique<MemCpyVolatileOperation>(length.Type(), memoryStates.size());
282 return ThreeAddressCode::create(std::move(operation), operands);
283 }
284
285 static rvsdg::SimpleNode &
287 rvsdg::Output & destination,
288 rvsdg::Output & source,
289 rvsdg::Output & length,
290 rvsdg::Output & ioState,
291 const std::vector<rvsdg::Output *> & memoryStates)
292 {
293 std::vector operands = { &destination, &source, &length, &ioState };
294 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
295
297 operands,
298 length.Type(),
299 memoryStates.size());
300 }
301
302private:
303 static std::vector<std::shared_ptr<const rvsdg::Type>>
304 CreateOperandTypes(std::shared_ptr<const rvsdg::Type> lengthType, size_t numMemoryStates)
305 {
306 auto pointerType = PointerType::Create();
307 std::vector<std::shared_ptr<const rvsdg::Type>> types = { pointerType,
308 pointerType,
309 std::move(lengthType),
311 types.insert(types.end(), numMemoryStates, MemoryStateType::Create());
312 return types;
313 }
314
315 static std::vector<std::shared_ptr<const rvsdg::Type>>
316 CreateResultTypes(size_t numMemoryStates)
317 {
318 // The memcpy() standard C library call has as return type void*, but LLVM models the
319 // function call nevertheless as:
320 // call void @llvm.memcpy.p0.p0.i64(ptr align 4 %7, ptr align 4 %8, i64 %9, i1 false)
321 //
322 // LLVM simply hands in register %7 (dest pointer) to all users of the return type of memcpy().
323 // Thus, we only need state types as result types of the operation here.
324 std::vector<std::shared_ptr<const rvsdg::Type>> types(1, IOStateType::Create());
325 types.insert(types.end(), numMemoryStates, MemoryStateType::Create());
326 return types;
327 }
328};
329
336{
337protected:
339 const std::vector<std::shared_ptr<const rvsdg::Type>> & operandTypes,
340 const std::vector<std::shared_ptr<const rvsdg::Type>> & resultTypes)
341 : SimpleOperation(operandTypes, resultTypes)
342 {
343 JLM_ASSERT(operandTypes.size() >= 3);
344
345 auto & dstAddressType = *operandTypes[0];
346 JLM_ASSERT(is<PointerType>(dstAddressType));
347
348 if (auto & valueType = *operandTypes[1]; valueType != *rvsdg::BitType::Create(8))
349 {
350 throw std::runtime_error("Expected 8 bit integer type.");
351 }
352
353 if (auto & lengthType = *operandTypes[2];
355 {
356 throw util::Error("Expected 32 bit or 64 bit integer type.");
357 }
358 }
359
360public:
364 [[nodiscard]] const rvsdg::BitType &
365 lengthType() const noexcept
366 {
367 const auto type = std::dynamic_pointer_cast<const rvsdg::BitType>(argument(2));
368 JLM_ASSERT(type != nullptr);
369 JLM_ASSERT(type->nbits() == 32 || type->nbits() == 64);
370 return *type;
371 }
372
376 [[nodiscard]] virtual size_t
377 numMemoryStates() const noexcept = 0;
378
383 [[nodiscard]] static rvsdg::Input &
384 destinationInput(const rvsdg::Node & node) noexcept
385 {
386 JLM_ASSERT(is<MemSetOperation>(&node));
387 const auto input = node.input(0);
388 JLM_ASSERT(is<PointerType>(input->Type()));
389 return *input;
390 }
391
396 [[nodiscard]] static rvsdg::Input &
397 valueInput(const rvsdg::Node & node) noexcept
398 {
399 JLM_ASSERT(is<MemSetOperation>(&node));
400 const auto input = node.input(1);
401 JLM_ASSERT(*input->Type() == *rvsdg::BitType::Create(8));
402 return *input;
403 }
404
409 [[nodiscard]] static rvsdg::Input &
410 lengthInput(const rvsdg::Node & node) noexcept
411 {
412 JLM_ASSERT(is<MemSetOperation>(&node));
413 const auto input = node.input(2);
415 *input->Type() == *rvsdg::BitType::Create(32)
416 || *input->Type() == *rvsdg::BitType::Create(64));
417 return *input;
418 }
419
423 [[nodiscard]] static rvsdg::Input &
425 {
426 JLM_ASSERT(is<MemoryStateType>(output.Type()));
427 auto [memsetNode, memsetOperation] =
429 JLM_ASSERT(memsetOperation);
430 const auto numNonMemoryStateOutputs =
431 memsetNode->noutputs() - memsetOperation->numMemoryStates();
432 JLM_ASSERT(output.index() >= numNonMemoryStateOutputs);
433 const auto numNonMemoryStateInputs = memsetNode->ninputs() - memsetOperation->numMemoryStates();
434 const auto inputIndex = numNonMemoryStateInputs + (output.index() - numNonMemoryStateOutputs);
435 const auto input = memsetNode->input(inputIndex);
436 JLM_ASSERT(is<MemoryStateType>(input->Type()));
437 return *input;
438 }
439
443 [[nodiscard]] static rvsdg::Output &
445 {
446 JLM_ASSERT(is<MemoryStateType>(input.Type()));
447 auto [memsetNode, memsetOperation] =
449 JLM_ASSERT(memsetOperation);
450 const auto numNonMemoryStateInputs = memsetNode->ninputs() - memsetOperation->numMemoryStates();
451 JLM_ASSERT(input.index() >= numNonMemoryStateInputs);
452 const auto numNonMemoryStateOutputs =
453 memsetNode->noutputs() - memsetOperation->numMemoryStates();
454 const auto outputIndex = numNonMemoryStateOutputs + (input.index() - numNonMemoryStateInputs);
455 const auto output = memsetNode->output(outputIndex);
456 JLM_ASSERT(is<MemoryStateType>(output->Type()));
457 return *output;
458 }
459};
460
468{
469public:
470 ~MemSetNonVolatileOperation() noexcept override;
471
477
478 bool
479 operator==(const Operation & other) const noexcept override;
480
481 [[nodiscard]] std::string
482 debug_string() const override;
483
484 [[nodiscard]] std::unique_ptr<Operation>
485 copy() const override;
486
487 [[nodiscard]] size_t
488 numMemoryStates() const noexcept override;
489
490 static std::unique_ptr<ThreeAddressCode>
492 const Variable & destination,
493 const Variable & value,
494 const Variable & length,
495 const std::vector<const Variable *> & memoryStates)
496 {
497 std::vector operands = { &destination, &value, &length };
498 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
499
500 auto operation =
501 std::make_unique<MemSetNonVolatileOperation>(length.Type(), memoryStates.size());
502 return ThreeAddressCode::create(std::move(operation), operands);
503 }
504
505 static rvsdg::SimpleNode &
507 rvsdg::Output & destination,
508 rvsdg::Output & value,
509 rvsdg::Output & length,
510 const std::vector<rvsdg::Output *> & memoryStates)
511 {
512 std::vector operands = { &destination, &value, &length };
513 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
514
516 operands,
517 length.Type(),
518 memoryStates.size());
519 }
520
521private:
522 static std::vector<std::shared_ptr<const rvsdg::Type>>
524 const std::shared_ptr<const rvsdg::Type> & lengthType,
525 const size_t numMemoryStates)
526 {
527 const auto pointerType = PointerType::Create();
528 const auto & valueType = rvsdg::BitType::Create(8);
529 std::vector<std::shared_ptr<const rvsdg::Type>> types = { pointerType, valueType, lengthType };
530 types.insert(types.end(), numMemoryStates, MemoryStateType::Create());
531 return types;
532 }
533
534 static std::vector<std::shared_ptr<const rvsdg::Type>>
536 {
537 // The memset() standard C library call has as return type void*, but LLVM models the
538 // function call nevertheless as:
539 // call void @llvm.memset.p0.i64(ptr %0, i8 0, i64 8, i1 false)
540 //
541 // LLVM simply hands in register %7 (dest pointer) to all users of the return type of memset().
542 // Thus, we only need state types as result types of the operation here.
544 }
545};
546
556{
557protected:
559 const std::vector<std::shared_ptr<const rvsdg::Type>> & operandTypes,
560 const std::vector<std::shared_ptr<const rvsdg::Type>> & resultTypes)
561 : SimpleOperation(operandTypes, resultTypes)
562 {
563 JLM_ASSERT(operandTypes.size() >= 3);
564
565 auto & destAddressType = *operandTypes[0];
566 JLM_ASSERT(is<PointerType>(destAddressType));
567
568 auto & srcAddressType = *operandTypes[1];
569 JLM_ASSERT(is<PointerType>(srcAddressType));
570
571 auto & lengthType = *operandTypes[2];
574 }
575
576public:
580 [[nodiscard]] const rvsdg::BitType &
581 lengthType() const noexcept
582 {
583 const auto type = std::dynamic_pointer_cast<const rvsdg::BitType>(argument(2));
584 JLM_ASSERT(type != nullptr);
585 JLM_ASSERT(type->nbits() == 32 || type->nbits() == 64);
586 return *type;
587 }
588
592 [[nodiscard]] virtual size_t
593 numMemoryStates() const noexcept = 0;
594
599 [[nodiscard]] static rvsdg::Input &
600 destinationInput(const rvsdg::Node & node) noexcept
601 {
602 JLM_ASSERT(is<MemMoveOperation>(&node));
603 const auto input = node.input(0);
604 JLM_ASSERT(is<PointerType>(input->Type()));
605 return *input;
606 }
607
612 [[nodiscard]] static rvsdg::Input &
613 sourceInput(const rvsdg::Node & node) noexcept
614 {
615 JLM_ASSERT(is<MemMoveOperation>(&node));
616 const auto input = node.input(1);
617 JLM_ASSERT(is<PointerType>(input->Type()));
618 return *input;
619 }
620
625 [[nodiscard]] static rvsdg::Input &
626 lengthInput(const rvsdg::Node & node) noexcept
627 {
628 JLM_ASSERT(is<MemMoveOperation>(&node));
629 const auto input = node.input(2);
630 const auto type = std::dynamic_pointer_cast<const rvsdg::BitType>(node.input(2)->Type());
631 JLM_ASSERT(type != nullptr);
632 JLM_ASSERT(type->nbits() == 32 || type->nbits() == 64);
633 return *input;
634 }
635
639 [[nodiscard]] static rvsdg::Input &
641 {
642 JLM_ASSERT(is<MemoryStateType>(output.Type()));
643 auto [memmoveNode, memmoveOperation] =
645 JLM_ASSERT(memmoveOperation);
646 const auto numNonMemoryStateOutputs =
647 memmoveNode->noutputs() - memmoveOperation->numMemoryStates();
648 JLM_ASSERT(output.index() >= numNonMemoryStateOutputs);
649 const auto numNonMemoryStateInputs =
650 memmoveNode->ninputs() - memmoveOperation->numMemoryStates();
651 const auto inputIndex = numNonMemoryStateInputs + (output.index() - numNonMemoryStateOutputs);
652 const auto input = memmoveNode->input(inputIndex);
653 JLM_ASSERT(is<MemoryStateType>(input->Type()));
654 return *input;
655 }
656
660 [[nodiscard]] static rvsdg::Output &
662 {
663 JLM_ASSERT(is<MemoryStateType>(input.Type()));
664 auto [memmoveNode, memmoveOperation] =
666 JLM_ASSERT(memmoveOperation);
667 const auto numNonMemoryStateInputs =
668 memmoveNode->ninputs() - memmoveOperation->numMemoryStates();
669 JLM_ASSERT(input.index() >= numNonMemoryStateInputs);
670 const auto numNonMemoryStateOutputs =
671 memmoveNode->noutputs() - memmoveOperation->numMemoryStates();
672 const auto outputIndex = numNonMemoryStateOutputs + (input.index() - numNonMemoryStateInputs);
673 const auto output = memmoveNode->output(outputIndex);
674 JLM_ASSERT(is<MemoryStateType>(output->Type()));
675 return *output;
676 }
677};
678
686{
687public:
688 ~MemMoveNonVolatileOperation() noexcept override;
689
695
696 bool
697 operator==(const Operation & other) const noexcept override;
698
699 [[nodiscard]] std::string
700 debug_string() const override;
701
702 [[nodiscard]] std::unique_ptr<Operation>
703 copy() const override;
704
705 [[nodiscard]] size_t
706 numMemoryStates() const noexcept override;
707
708 static std::unique_ptr<ThreeAddressCode>
710 const Variable & dest,
711 const Variable & src,
712 const Variable & length,
713 const std::vector<const Variable *> & memoryStates)
714 {
715 std::vector operands = { &dest, &src, &length };
716 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
717
718 auto operation =
719 std::make_unique<MemMoveNonVolatileOperation>(length.Type(), memoryStates.size());
720 return ThreeAddressCode::create(std::move(operation), operands);
721 }
722
723 static rvsdg::SimpleNode &
725 rvsdg::Output & dest,
726 rvsdg::Output & src,
727 rvsdg::Output & length,
728 const std::vector<rvsdg::Output *> & memoryStates)
729 {
730 std::vector operands = { &dest, &src, &length };
731 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
732
734 operands,
735 length.Type(),
736 memoryStates.size());
737 }
738
739private:
740 static std::vector<std::shared_ptr<const rvsdg::Type>>
742 const std::shared_ptr<const rvsdg::Type> & lengthType,
743 const size_t numMemoryStates)
744 {
745 const auto bitType = std::dynamic_pointer_cast<const rvsdg::BitType>(lengthType);
746 if (!bitType || (bitType->nbits() != 32 && bitType->nbits() != 64))
747 {
748 throw std::runtime_error("lengthType must be a 32-bit or 64-bit integer type");
749 }
750
751 std::vector<std::shared_ptr<const rvsdg::Type>> types = { PointerType::Create(),
753 lengthType };
754 types.insert(types.end(), numMemoryStates, MemoryStateType::Create());
755 return types;
756 }
757
758 static std::vector<std::shared_ptr<const rvsdg::Type>>
760 {
761 // The memmove() standard C library call has as return type void*, but LLVM models the
762 // function call nevertheless as:
763 // call void @llvm.memmove.p0.p0.i64(ptr %0, i8 0, i64 8, i1 false)
764 //
765 // LLVM simply hands in register %7 (dest pointer) to all users of the return type of memmove().
766 // Thus, we only need state types as result types of the operation here.
768 }
769};
770
778{
779public:
780 ~UMaxOperation() noexcept override;
781
782 explicit UMaxOperation(const std::shared_ptr<const rvsdg::Type> & type)
783 : SimpleOperation({ type, type }, { type })
784 {
785 checkType(type);
786 }
787
788 bool
789 operator==(const Operation & other) const noexcept override;
790
791 std::string
792 debug_string() const override;
793
794 [[nodiscard]] std::unique_ptr<Operation>
795 copy() const override;
796
797 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
798 getType() const noexcept
799 {
800 return result(0);
801 }
802
803 static std::unique_ptr<ThreeAddressCode>
804 createTac(const Variable & operand1, const Variable & operand2)
805 {
806 auto operation = std::make_unique<UMaxOperation>(operand1.Type());
807 return ThreeAddressCode::create(std::move(operation), { &operand1, &operand2 });
808 }
809
810 static rvsdg::SimpleNode &
811 createNode(rvsdg::Output & operand1, rvsdg::Output & operand2)
812 {
814 {
815 &operand1,
816 &operand2,
817 },
818 operand1.Type());
819 }
820
821private:
822 static void
823 checkType(const std::shared_ptr<const rvsdg::Type> & type);
824};
825
833{
834public:
835 ~SMinOperation() noexcept override;
836
837 explicit SMinOperation(const std::shared_ptr<const rvsdg::Type> & type)
838 : SimpleOperation({ type, type }, { type })
839 {
840 checkType(type);
841 }
842
843 bool
844 operator==(const Operation & other) const noexcept override;
845
846 std::string
847 debug_string() const override;
848
849 [[nodiscard]] std::unique_ptr<Operation>
850 copy() const override;
851
852 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
853 getType() const noexcept
854 {
855 return result(0);
856 }
857
858 static std::unique_ptr<ThreeAddressCode>
859 createTac(const Variable & operand1, const Variable & operand2)
860 {
861 auto operation = std::make_unique<SMinOperation>(operand1.Type());
862 return ThreeAddressCode::create(std::move(operation), { &operand1, &operand2 });
863 }
864
865 static rvsdg::SimpleNode &
866 createNode(rvsdg::Output & operand1, rvsdg::Output & operand2)
867 {
869 {
870 &operand1,
871 &operand2,
872 },
873 operand1.Type());
874 }
875
876private:
877 static void
878 checkType(const std::shared_ptr<const rvsdg::Type> & type);
879};
880
888{
889public:
890 ~UMinOperation() noexcept override;
891
892 explicit UMinOperation(const std::shared_ptr<const rvsdg::Type> & type)
893 : SimpleOperation({ type, type }, { type })
894 {
895 checkType(type);
896 }
897
898 bool
899 operator==(const Operation & other) const noexcept override;
900
901 std::string
902 debug_string() const override;
903
904 [[nodiscard]] std::unique_ptr<Operation>
905 copy() const override;
906
907 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
908 getType() const noexcept
909 {
910 return result(0);
911 }
912
913 static std::unique_ptr<ThreeAddressCode>
914 createTac(const Variable & operand1, const Variable & operand2)
915 {
916 auto operation = std::make_unique<UMinOperation>(operand1.Type());
917 return ThreeAddressCode::create(std::move(operation), { &operand1, &operand2 });
918 }
919
920 static rvsdg::SimpleNode &
921 createNode(rvsdg::Output & operand1, rvsdg::Output & operand2)
922 {
924 {
925 &operand1,
926 &operand2,
927 },
928 operand1.Type());
929 }
930
931private:
932 static void
933 checkType(const std::shared_ptr<const rvsdg::Type> & type);
934};
935
943{
944public:
945 ~FAbsOperation() noexcept override;
946
947 explicit FAbsOperation(const std::shared_ptr<const rvsdg::Type> & type)
948 : UnaryOperation(type, type)
949 {
950 checkType(type);
951 }
952
953 bool
954 operator==(const Operation & other) const noexcept override;
955
956 std::string
957 debug_string() const override;
958
959 [[nodiscard]] std::unique_ptr<Operation>
960 copy() const override;
961
962 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
963 getType() const noexcept
964 {
965 return result(0);
966 }
967
968 static std::unique_ptr<ThreeAddressCode>
969 createTac(const Variable & operand)
970 {
971 auto operation = std::make_unique<FAbsOperation>(operand.Type());
972 return ThreeAddressCode::create(std::move(operation), { &operand });
973 }
974
975 static rvsdg::SimpleNode &
977 {
979 {
980 &operand,
981 },
982 operand.Type());
983 }
984
985private:
986 static void
987 checkType(const std::shared_ptr<const rvsdg::Type> & type);
988};
989
997{
998public:
999 ~AbsOperation() noexcept override;
1000
1001 explicit AbsOperation(const std::shared_ptr<const rvsdg::Type> & type)
1002 : SimpleOperation({ type, rvsdg::BitType::Create(1) }, { type })
1003 {
1004 checkType(type);
1005 }
1006
1007 bool
1008 operator==(const Operation & other) const noexcept override;
1009
1010 std::string
1011 debug_string() const override;
1012
1013 [[nodiscard]] std::unique_ptr<Operation>
1014 copy() const override;
1015
1016 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
1017 getType() const noexcept
1018 {
1019 return result(0);
1020 }
1021
1022 static std::unique_ptr<ThreeAddressCode>
1023 createTac(const Variable & operand1, const Variable & operand2)
1024 {
1025 auto operation = std::make_unique<AbsOperation>(operand1.Type());
1026 return ThreeAddressCode::create(std::move(operation), { &operand1, &operand2 });
1027 }
1028
1029 static rvsdg::SimpleNode &
1031 {
1033 {
1034 &operand1,
1035 &operand2,
1036 },
1037 operand1.Type());
1038 }
1039
1040private:
1041 static void
1042 checkType(const std::shared_ptr<const rvsdg::Type> & type);
1043};
1044
1052{
1053public:
1054 ~SMaxOperation() noexcept override;
1055
1056 explicit SMaxOperation(const std::shared_ptr<const rvsdg::Type> & type)
1057 : SimpleOperation({ type, type }, { type })
1058 {
1059 checkType(type);
1060 }
1061
1062 bool
1063 operator==(const Operation & other) const noexcept override;
1064
1065 std::string
1066 debug_string() const override;
1067
1068 [[nodiscard]] std::unique_ptr<Operation>
1069 copy() const override;
1070
1071 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
1072 getType() const noexcept
1073 {
1074 return result(0);
1075 }
1076
1077 static std::unique_ptr<ThreeAddressCode>
1078 createTac(const Variable & operand1, const Variable & operand2)
1079 {
1080 auto operation = std::make_unique<SMaxOperation>(operand1.Type());
1081 return ThreeAddressCode::create(std::move(operation), { &operand1, &operand2 });
1082 }
1083
1084 static rvsdg::SimpleNode &
1086 {
1088 {
1089 &operand1,
1090 &operand2,
1091 },
1092 operand1.Type());
1093 }
1094
1095private:
1096 static void
1097 checkType(const std::shared_ptr<const rvsdg::Type> & type);
1098};
1099
1100}
1101
1102#endif
~AbsOperation() noexcept override
static rvsdg::SimpleNode & createNode(rvsdg::Output &operand1, rvsdg::Output &operand2)
bool operator==(const Operation &other) const noexcept override
std::shared_ptr< const rvsdg::Type > getType() const noexcept
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &operand1, const Variable &operand2)
static void checkType(const std::shared_ptr< const rvsdg::Type > &type)
std::unique_ptr< Operation > copy() const override
std::string debug_string() const override
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &operand)
std::string debug_string() const override
bool operator==(const Operation &other) const noexcept override
~FAbsOperation() noexcept override
std::unique_ptr< Operation > copy() const override
static void checkType(const std::shared_ptr< const rvsdg::Type > &type)
std::shared_ptr< const rvsdg::Type > getType() const noexcept
static rvsdg::SimpleNode & createNode(rvsdg::Output &operand)
static std::shared_ptr< const IOStateType > Create()
Definition types.cpp:343
std::unique_ptr< Operation > copy() const override
MemCpyNonVolatileOperation(std::shared_ptr< const rvsdg::Type > lengthType, size_t numMemoryStates)
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateResultTypes(size_t numMemoryStates)
size_t NumMemoryStates() const noexcept override
static std::vector< rvsdg::Output * > create(rvsdg::Output *destination, rvsdg::Output *source, rvsdg::Output *length, const std::vector< rvsdg::Output * > &memoryStates)
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateOperandTypes(std::shared_ptr< const rvsdg::Type > length, size_t numMemoryStates)
bool operator==(const Operation &other) const noexcept override
static rvsdg::SimpleNode & createNode(rvsdg::Output &destination, rvsdg::Output &source, rvsdg::Output &length, const std::vector< rvsdg::Output * > &memoryStates)
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *destination, const Variable *source, const Variable *length, const std::vector< const Variable * > &memoryStates)
MemCpyOperation(const std::vector< std::shared_ptr< const rvsdg::Type > > &operandTypes, const std::vector< std::shared_ptr< const rvsdg::Type > > &resultTypes)
const rvsdg::BitType & LengthType() const noexcept
virtual size_t NumMemoryStates() const noexcept=0
static rvsdg::Input & sourceInput(const rvsdg::Node &node) noexcept
static rvsdg::Output & mapMemoryStateInputToOutput(const rvsdg::Input &input)
static rvsdg::Input & destinationInput(const rvsdg::Node &node) noexcept
static rvsdg::Input & countInput(const rvsdg::Node &node) noexcept
static rvsdg::Input & mapMemoryStateOutputToInput(const rvsdg::Output &output)
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateResultTypes(size_t numMemoryStates)
std::unique_ptr< Operation > copy() const override
~MemCpyVolatileOperation() noexcept override
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &destination, rvsdg::Output &source, rvsdg::Output &length, rvsdg::Output &ioState, const std::vector< rvsdg::Output * > &memoryStates)
static std::unique_ptr< llvm::ThreeAddressCode > CreateThreeAddressCode(const Variable &destination, const Variable &source, const Variable &length, const Variable &ioState, const std::vector< const Variable * > &memoryStates)
bool operator==(const Operation &other) const noexcept override
size_t NumMemoryStates() const noexcept override
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateOperandTypes(std::shared_ptr< const rvsdg::Type > lengthType, size_t numMemoryStates)
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &dest, const Variable &src, const Variable &length, const std::vector< const Variable * > &memoryStates)
static std::vector< std::shared_ptr< const rvsdg::Type > > createResultTypes(size_t numMemoryStates)
size_t numMemoryStates() const noexcept override
std::unique_ptr< Operation > copy() const override
~MemMoveNonVolatileOperation() noexcept override
static std::vector< std::shared_ptr< const rvsdg::Type > > checkAndCreateOperandTypes(const std::shared_ptr< const rvsdg::Type > &lengthType, const size_t numMemoryStates)
static rvsdg::SimpleNode & createNode(rvsdg::Output &dest, rvsdg::Output &src, rvsdg::Output &length, const std::vector< rvsdg::Output * > &memoryStates)
bool operator==(const Operation &other) const noexcept override
virtual size_t numMemoryStates() const noexcept=0
static rvsdg::Input & destinationInput(const rvsdg::Node &node) noexcept
static rvsdg::Output & mapMemoryStateInputToOutput(const rvsdg::Input &input)
static rvsdg::Input & lengthInput(const rvsdg::Node &node) noexcept
const rvsdg::BitType & lengthType() const noexcept
static rvsdg::Input & mapMemoryStateOutputToInput(const rvsdg::Output &output)
MemMoveOperation(const std::vector< std::shared_ptr< const rvsdg::Type > > &operandTypes, const std::vector< std::shared_ptr< const rvsdg::Type > > &resultTypes)
static rvsdg::Input & sourceInput(const rvsdg::Node &node) noexcept
size_t numMemoryStates() const noexcept override
static std::vector< std::shared_ptr< const rvsdg::Type > > createOperandTypes(const std::shared_ptr< const rvsdg::Type > &lengthType, const size_t numMemoryStates)
~MemSetNonVolatileOperation() noexcept override
static std::vector< std::shared_ptr< const rvsdg::Type > > createResultTypes(size_t numMemoryStates)
static rvsdg::SimpleNode & createNode(rvsdg::Output &destination, rvsdg::Output &value, rvsdg::Output &length, const std::vector< rvsdg::Output * > &memoryStates)
bool operator==(const Operation &other) const noexcept override
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &destination, const Variable &value, const Variable &length, const std::vector< const Variable * > &memoryStates)
std::unique_ptr< Operation > copy() const override
MemSetOperation(const std::vector< std::shared_ptr< const rvsdg::Type > > &operandTypes, const std::vector< std::shared_ptr< const rvsdg::Type > > &resultTypes)
static rvsdg::Input & valueInput(const rvsdg::Node &node) noexcept
virtual size_t numMemoryStates() const noexcept=0
static rvsdg::Input & lengthInput(const rvsdg::Node &node) noexcept
const rvsdg::BitType & lengthType() const noexcept
static rvsdg::Output & mapMemoryStateInputToOutput(const rvsdg::Input &input)
static rvsdg::Input & mapMemoryStateOutputToInput(const rvsdg::Output &output)
static rvsdg::Input & destinationInput(const rvsdg::Node &node) noexcept
static std::shared_ptr< const MemoryStateType > Create()
Definition types.cpp:379
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
static void checkType(const std::shared_ptr< const rvsdg::Type > &type)
std::string debug_string() const override
~SMaxOperation() noexcept override
std::unique_ptr< Operation > copy() const override
static rvsdg::SimpleNode & createNode(rvsdg::Output &operand1, rvsdg::Output &operand2)
bool operator==(const Operation &other) const noexcept override
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &operand1, const Variable &operand2)
std::shared_ptr< const rvsdg::Type > getType() const noexcept
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &operand1, const Variable &operand2)
~SMinOperation() noexcept override
bool operator==(const Operation &other) const noexcept override
std::string debug_string() const override
std::shared_ptr< const rvsdg::Type > getType() const noexcept
static rvsdg::SimpleNode & createNode(rvsdg::Output &operand1, rvsdg::Output &operand2)
std::unique_ptr< Operation > copy() const override
static void checkType(const std::shared_ptr< const rvsdg::Type > &type)
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition tac.hpp:135
std::shared_ptr< const rvsdg::Type > getType() const noexcept
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &operand1, const Variable &operand2)
static void checkType(const std::shared_ptr< const rvsdg::Type > &type)
std::unique_ptr< Operation > copy() const override
std::string debug_string() const override
static rvsdg::SimpleNode & createNode(rvsdg::Output &operand1, rvsdg::Output &operand2)
bool operator==(const Operation &other) const noexcept override
~UMaxOperation() noexcept override
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &operand1, const Variable &operand2)
std::unique_ptr< Operation > copy() const override
~UMinOperation() noexcept override
static rvsdg::SimpleNode & createNode(rvsdg::Output &operand1, rvsdg::Output &operand2)
std::string debug_string() const override
std::shared_ptr< const rvsdg::Type > getType() const noexcept
static void checkType(const std::shared_ptr< const rvsdg::Type > &type)
bool operator==(const Operation &other) const noexcept override
const std::shared_ptr< const jlm::rvsdg::Type > Type() const noexcept
Definition variable.hpp:62
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
Definition type.cpp:45
size_t index() const noexcept
Definition node.hpp:52
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:67
size_t index() const noexcept
Definition node.hpp:274
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
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
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
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
Global memory state passed between functions.
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872