Jlm
Loading...
Searching...
No Matches
MemoryStateOperations.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#ifndef JLM_LLVM_IR_OPERATORS_MEMORYSTATEOPERATIONS_HPP
7#define JLM_LLVM_IR_OPERATORS_MEMORYSTATEOPERATIONS_HPP
8
9#include <jlm/llvm/ir/tac.hpp>
10#include <jlm/llvm/ir/types.hpp>
13
14namespace jlm::llvm
15{
16
17using MemoryNodeId = std::size_t;
18
23{
24protected:
25 MemoryStateOperation(size_t numOperands, size_t numResults)
27 { numOperands, MemoryStateType::Create() },
28 { numResults, MemoryStateType::Create() })
29 {}
30};
31
39{
40public:
41 ~MemoryStateMergeOperation() noexcept override;
42
43 explicit MemoryStateMergeOperation(size_t numOperands)
44 : MemoryStateOperation(numOperands, 1)
45 {
46 if (numOperands == 0)
47 throw util::Error("Insufficient number of operands.");
48 }
49
50 bool
51 operator==(const Operation & other) const noexcept override;
52
53 [[nodiscard]] std::string
54 debug_string() const override;
55
56 [[nodiscard]] std::unique_ptr<Operation>
57 copy() const override;
58
67 static std::optional<std::vector<rvsdg::Output *>>
69 const MemoryStateMergeOperation & operation,
70 const std::vector<rvsdg::Output *> & operands);
71
78 static std::optional<std::vector<rvsdg::Output *>>
80 const MemoryStateMergeOperation & operation,
81 const std::vector<rvsdg::Output *> & operands);
82
90 static std::optional<std::vector<rvsdg::Output *>>
92 const MemoryStateMergeOperation & operation,
93 const std::vector<rvsdg::Output *> & operands);
94
102 static std::optional<std::vector<rvsdg::Output *>>
104 const MemoryStateMergeOperation & operation,
105 const std::vector<rvsdg::Output *> & operands);
106
107 static rvsdg::SimpleNode &
108 CreateNode(const std::vector<rvsdg::Output *> & operands)
109 {
110 return rvsdg::CreateOpNode<MemoryStateMergeOperation>(operands, operands.size());
111 }
112
113 static rvsdg::Output *
114 Create(const std::vector<rvsdg::Output *> & operands)
115 {
116 return CreateNode(operands).output(0);
117 }
118
119 static std::unique_ptr<ThreeAddressCode>
120 Create(const std::vector<const Variable *> & operands)
121 {
122 if (operands.empty())
123 throw util::Error("Insufficient number of operands.");
124
125 auto operation = std::make_unique<MemoryStateMergeOperation>(operands.size());
126 return ThreeAddressCode::create(std::move(operation), operands);
127 }
128};
129
137{
138public:
139 ~MemoryStateJoinOperation() noexcept override;
140
141 explicit MemoryStateJoinOperation(const size_t numOperands)
142 : MemoryStateOperation(numOperands, 1)
143 {
144 if (numOperands == 0)
145 throw std::logic_error("Insufficient number of operands.");
146 }
147
148 bool
149 operator==(const Operation & other) const noexcept override;
150
151 [[nodiscard]] std::string
152 debug_string() const override;
153
154 [[nodiscard]] std::unique_ptr<Operation>
155 copy() const override;
156
165 static std::optional<std::vector<rvsdg::Output *>>
167 const MemoryStateJoinOperation & operation,
168 const std::vector<rvsdg::Output *> & operands);
169
176 static std::optional<std::vector<rvsdg::Output *>>
178 const MemoryStateJoinOperation & operation,
179 const std::vector<rvsdg::Output *> & operands);
180
188 static std::optional<std::vector<rvsdg::Output *>>
190 const MemoryStateJoinOperation & operation,
191 const std::vector<rvsdg::Output *> & operands);
192
193 static rvsdg::SimpleNode &
194 CreateNode(const std::vector<rvsdg::Output *> & operands)
195 {
196 return rvsdg::CreateOpNode<MemoryStateJoinOperation>(operands, operands.size());
197 }
198};
199
207{
208public:
209 ~MemoryStateSplitOperation() noexcept override;
210
211 explicit MemoryStateSplitOperation(const size_t numResults)
212 : MemoryStateOperation(1, numResults)
213 {
214 if (numResults == 0)
215 throw util::Error("Insufficient number of results.");
216 }
217
218 bool
219 operator==(const Operation & other) const noexcept override;
220
221 [[nodiscard]] std::string
222 debug_string() const override;
223
224 [[nodiscard]] std::unique_ptr<Operation>
225 copy() const override;
226
235 static std::optional<std::vector<rvsdg::Output *>>
237 const MemoryStateSplitOperation & operation,
238 const std::vector<rvsdg::Output *> & operands);
239
247 static std::optional<std::vector<rvsdg::Output *>>
249 const MemoryStateSplitOperation & operation,
250 const std::vector<rvsdg::Output *> & operands);
251
260 static std::optional<std::vector<rvsdg::Output *>>
262 const MemoryStateSplitOperation & operation,
263 const std::vector<rvsdg::Output *> & operands);
264
265 static rvsdg::SimpleNode &
266 CreateNode(rvsdg::Output & operand, const size_t numResults)
267 {
268 return rvsdg::CreateOpNode<MemoryStateSplitOperation>({ &operand }, numResults);
269 }
270
271 static std::vector<rvsdg::Output *>
272 Create(rvsdg::Output & operand, const size_t numResults)
273 {
274 return outputs(&CreateNode(operand, numResults));
275 }
276};
277
289{
290public:
292
293 explicit LambdaEntryMemoryStateSplitOperation(const std::vector<MemoryNodeId> & memoryNodeIds);
294
295 bool
296 operator==(const Operation & other) const noexcept override;
297
298 [[nodiscard]] std::string
299 debug_string() const override;
300
301 [[nodiscard]] std::unique_ptr<Operation>
302 copy() const override;
303
307 [[nodiscard]] std::vector<MemoryNodeId>
308 getMemoryNodeIds() const noexcept
309 {
310 std::vector<MemoryNodeId> memoryNodeIds(nresults());
311 for (auto [memoryNodeId, index] : memoryNodeIdToIndexMap_)
312 {
313 JLM_ASSERT(index < nresults());
314 memoryNodeIds[index] = memoryNodeId;
315 }
316
317 return memoryNodeIds;
318 }
319
328 [[nodiscard]] static rvsdg::Output *
330
340 [[nodiscard]] static MemoryNodeId
342
343 static rvsdg::SimpleNode &
344 CreateNode(rvsdg::Output & operand, std::vector<MemoryNodeId> memoryNodeIds)
345 {
347 { &operand },
348 std::move(memoryNodeIds));
349 }
350
351private:
353};
354
366{
367public:
369
370 explicit LambdaExitMemoryStateMergeOperation(const std::vector<MemoryNodeId> & memoryNodeIds);
371
372 bool
373 operator==(const Operation & other) const noexcept override;
374
375 [[nodiscard]] std::string
376 debug_string() const override;
377
378 [[nodiscard]] std::unique_ptr<Operation>
379 copy() const override;
380
384 [[nodiscard]] std::vector<MemoryNodeId>
385 getMemoryNodeIds() const noexcept
386 {
387 std::vector<MemoryNodeId> memoryNodeIds(narguments());
388 for (auto [memoryNodeId, index] : MemoryNodeIdToIndex_)
389 {
390 JLM_ASSERT(index < narguments());
391 memoryNodeIds[index] = memoryNodeId;
392 }
393
394 return memoryNodeIds;
395 }
396
405 [[nodiscard]] static rvsdg::Input *
406 tryMapMemoryNodeIdToInput(const rvsdg::SimpleNode & node, MemoryNodeId memoryNodeId);
407
417 [[nodiscard]] static MemoryNodeId
419
431 static std::optional<std::vector<rvsdg::Output *>>
433 const LambdaExitMemoryStateMergeOperation & operation,
434 const std::vector<rvsdg::Output *> & operands);
435
447 static std::optional<std::vector<rvsdg::Output *>>
449 const LambdaExitMemoryStateMergeOperation & operation,
450 const std::vector<rvsdg::Output *> & operands);
451
462 static std::optional<std::vector<rvsdg::Output *>>
464 const LambdaExitMemoryStateMergeOperation & operation,
465 const std::vector<rvsdg::Output *> & operands);
466
467 static rvsdg::SimpleNode &
469 rvsdg::Region & region,
470 const std::vector<rvsdg::Output *> & operands,
471 const std::vector<MemoryNodeId> & memoryNodeIds)
472 {
473 return operands.empty()
476 }
477
478private:
480};
481
493{
494public:
496
497 explicit CallEntryMemoryStateMergeOperation(const std::vector<MemoryNodeId> & memoryNodeIds);
498
499 bool
500 operator==(const Operation & other) const noexcept override;
501
502 [[nodiscard]] std::string
503 debug_string() const override;
504
505 [[nodiscard]] std::unique_ptr<Operation>
506 copy() const override;
507
511 [[nodiscard]] std::vector<MemoryNodeId>
512 getMemoryNodeIds() const noexcept
513 {
514 std::vector<MemoryNodeId> memoryNodeIds(narguments());
515 for (auto [memoryNodeId, index] : MemoryNodeIdToIndex_)
516 {
517 JLM_ASSERT(index < narguments());
518 memoryNodeIds[index] = memoryNodeId;
519 }
520
521 return memoryNodeIds;
522 }
523
532 [[nodiscard]] static rvsdg::Input *
533 tryMapMemoryNodeIdToInput(const rvsdg::SimpleNode & node, MemoryNodeId memoryNodeId);
534
535 static rvsdg::SimpleNode &
537 rvsdg::Region & region,
538 const std::vector<rvsdg::Output *> & operands,
539 std::vector<MemoryNodeId> memoryNodeIds)
540 {
542 region,
543 std::move(memoryNodeIds))
545 operands,
546 std::move(memoryNodeIds));
547 }
548
549private:
551};
552
564{
565public:
567
568 explicit CallExitMemoryStateSplitOperation(const std::vector<MemoryNodeId> & memoryNodeIds);
569
570 bool
571 operator==(const Operation & other) const noexcept override;
572
573 [[nodiscard]] std::string
574 debug_string() const override;
575
576 [[nodiscard]] std::unique_ptr<Operation>
577 copy() const override;
578
582 [[nodiscard]] std::vector<MemoryNodeId>
583 getMemoryNodeIds() const noexcept
584 {
585 std::vector<MemoryNodeId> memoryNodeIds(nresults());
586 for (auto [memoryNodeId, index] : memoryNodeIdToIndexMap_)
587 {
588 JLM_ASSERT(index < nresults());
589 memoryNodeIds[index] = memoryNodeId;
590 }
591
592 return memoryNodeIds;
593 }
594
603 [[nodiscard]] static rvsdg::Output *
605
615 [[nodiscard]] static MemoryNodeId
617
618 static rvsdg::SimpleNode &
619 CreateNode(rvsdg::Output & operand, std::vector<MemoryNodeId> memoryNodeIds)
620 {
622 { &operand },
623 std::move(memoryNodeIds));
624 }
625
626private:
628};
629
636[[nodiscard]] bool
637hasMemoryState(const rvsdg::Node & node);
638
639}
640
641#endif
util::BijectiveMap< MemoryNodeId, size_t > MemoryNodeIdToIndex_
std::unique_ptr< Operation > copy() const override
std::vector< MemoryNodeId > getMemoryNodeIds() const noexcept
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands, std::vector< MemoryNodeId > memoryNodeIds)
~CallEntryMemoryStateMergeOperation() noexcept override
static rvsdg::Input * tryMapMemoryNodeIdToInput(const rvsdg::SimpleNode &node, MemoryNodeId memoryNodeId)
~CallExitMemoryStateSplitOperation() noexcept override
static MemoryNodeId mapOutputToMemoryNodeId(const rvsdg::Output &output)
util::BijectiveMap< MemoryNodeId, size_t > memoryNodeIdToIndexMap_
std::unique_ptr< Operation > copy() const override
static rvsdg::Output * tryMapMemoryNodeIdToOutput(const rvsdg::SimpleNode &node, MemoryNodeId memoryNodeId)
std::vector< MemoryNodeId > getMemoryNodeIds() const noexcept
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
util::BijectiveMap< MemoryNodeId, size_t > memoryNodeIdToIndexMap_
static rvsdg::Output * tryMapMemoryNodeIdToOutput(const rvsdg::SimpleNode &node, MemoryNodeId memoryNodeId)
std::unique_ptr< Operation > copy() const override
std::vector< MemoryNodeId > getMemoryNodeIds() const noexcept
static MemoryNodeId mapOutputToMemoryNodeId(const rvsdg::Output &output)
static std::optional< std::vector< rvsdg::Output * > > NormalizeLoadFromAlloca(const LambdaExitMemoryStateMergeOperation &operation, const std::vector< rvsdg::Output * > &operands)
static std::optional< std::vector< rvsdg::Output * > > NormalizeStoreToAlloca(const LambdaExitMemoryStateMergeOperation &operation, const std::vector< rvsdg::Output * > &operands)
util::BijectiveMap< MemoryNodeId, size_t > MemoryNodeIdToIndex_
std::vector< MemoryNodeId > getMemoryNodeIds() const noexcept
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands, const std::vector< MemoryNodeId > &memoryNodeIds)
static rvsdg::Input * tryMapMemoryNodeIdToInput(const rvsdg::SimpleNode &node, MemoryNodeId memoryNodeId)
std::unique_ptr< Operation > copy() const override
static std::optional< std::vector< rvsdg::Output * > > NormalizeAlloca(const LambdaExitMemoryStateMergeOperation &operation, const std::vector< rvsdg::Output * > &operands)
~LambdaExitMemoryStateMergeOperation() noexcept override
static MemoryNodeId mapInputToMemoryNodeId(const rvsdg::Input &input)
std::unique_ptr< Operation > copy() const override
static std::optional< std::vector< rvsdg::Output * > > NormalizeDuplicateOperands(const MemoryStateJoinOperation &operation, const std::vector< rvsdg::Output * > &operands)
Removes duplicated operands from the MemoryStateJoinOperation.
static std::optional< std::vector< rvsdg::Output * > > NormalizeNestedJoins(const MemoryStateJoinOperation &operation, const std::vector< rvsdg::Output * > &operands)
Fuses nested MemoryStateJoinOperation nodes into a single node.
static std::optional< std::vector< rvsdg::Output * > > NormalizeSingleOperand(const MemoryStateJoinOperation &operation, const std::vector< rvsdg::Output * > &operands)
Removes the MemoryStateJoinOperation as it has only a single operand, i.e., no joining is performed.
bool operator==(const Operation &other) const noexcept override
std::string debug_string() const override
~MemoryStateJoinOperation() noexcept override
static rvsdg::SimpleNode & CreateNode(const std::vector< rvsdg::Output * > &operands)
static std::optional< std::vector< rvsdg::Output * > > NormalizeNestedMerges(const MemoryStateMergeOperation &operation, const std::vector< rvsdg::Output * > &operands)
Fuses nested merges into a single merge.
static rvsdg::SimpleNode & CreateNode(const std::vector< rvsdg::Output * > &operands)
bool operator==(const Operation &other) const noexcept override
~MemoryStateMergeOperation() noexcept override
std::unique_ptr< Operation > copy() const override
static std::optional< std::vector< rvsdg::Output * > > NormalizeMergeSplit(const MemoryStateMergeOperation &operation, const std::vector< rvsdg::Output * > &operands)
Fuses nested splits into a single merge.
static std::optional< std::vector< rvsdg::Output * > > NormalizeSingleOperand(const MemoryStateMergeOperation &operation, const std::vector< rvsdg::Output * > &operands)
Removes the MemoryStateMergeOperation as it has only a single operand, i.e., no merging is performed.
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &operands)
static std::optional< std::vector< rvsdg::Output * > > NormalizeDuplicateOperands(const MemoryStateMergeOperation &operation, const std::vector< rvsdg::Output * > &operands)
Removes duplicated operands from the MemoryStateMergeOperation.
static std::unique_ptr< ThreeAddressCode > Create(const std::vector< const Variable * > &operands)
std::string debug_string() const override
MemoryStateOperation(size_t numOperands, size_t numResults)
static std::optional< std::vector< rvsdg::Output * > > NormalizeNestedSplits(const MemoryStateSplitOperation &operation, const std::vector< rvsdg::Output * > &operands)
Fuses nested splits into a single split.
~MemoryStateSplitOperation() noexcept override
bool operator==(const Operation &other) const noexcept override
static std::optional< std::vector< rvsdg::Output * > > NormalizeSingleResult(const MemoryStateSplitOperation &operation, const std::vector< rvsdg::Output * > &operands)
Removes the MemoryStateSplitOperation as it has only a single result, i.e., no splitting is performed...
static std::vector< rvsdg::Output * > Create(rvsdg::Output &operand, const size_t numResults)
std::unique_ptr< Operation > copy() const override
static std::optional< std::vector< rvsdg::Output * > > NormalizeSplitMerge(const MemoryStateSplitOperation &operation, const std::vector< rvsdg::Output * > &operands)
Removes an idempotent split-merge pair.
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, const size_t numResults)
static std::shared_ptr< const MemoryStateType > Create()
Definition types.cpp:379
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition tac.hpp:135
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
NodeOutput * output(size_t index) const noexcept
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
#define JLM_ASSERT(x)
Definition common.hpp:16
Global memory state passed between functions.
std::size_t MemoryNodeId
bool hasMemoryState(const rvsdg::Node &node)
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872