22 return operation && operation->
narguments() == narguments();
28 return "MemoryStateMerge";
31std::unique_ptr<rvsdg::Operation>
34 return std::make_unique<MemoryStateMergeOperation>(*
this);
37std::optional<std::vector<rvsdg::Output *>>
40 const std::vector<rvsdg::Output *> & operands)
42 if (operands.size() == 1)
43 return { { operands[0] } };
48std::optional<std::vector<rvsdg::Output *>>
51 const std::vector<rvsdg::Output *> & operands)
55 if (uniqueOperands.
Size() == operands.size())
62template<
class TMemoryStateMergeOrJoinOperation>
63std::vector<rvsdg::Output *>
67 std::is_same_v<TMemoryStateMergeOrJoinOperation, MemoryStateMergeOperation>
68 || std::is_same_v<TMemoryStateMergeOrJoinOperation, MemoryStateJoinOperation>,
69 "Template parameter T must be a MemoryStateMergeOperation or a MemoryStateJoinOperation!");
71 std::vector<rvsdg::Output *> newOperands;
72 for (
auto operand : operands)
74 auto [node, operation] =
79 CollectNestedMemoryStateMergeOrJoinOperands<TMemoryStateMergeOrJoinOperation>(
81 newOperands.insert(newOperands.end(), nodeOperands.begin(), nodeOperands.end());
85 newOperands.emplace_back(operand);
92std::optional<std::vector<rvsdg::Output *>>
95 const std::vector<rvsdg::Output *> & operands)
98 CollectNestedMemoryStateMergeOrJoinOperands<MemoryStateMergeOperation>(operands);
100 if (operands == newOperands)
107std::optional<std::vector<rvsdg::Output *>>
110 const std::vector<rvsdg::Output *> & operands)
112 std::vector<rvsdg::Output *> newOperands;
113 for (
const auto operand : operands)
115 auto [splitNode, splitOperation] =
119 newOperands.emplace_back(splitNode->input(0)->origin());
123 newOperands.emplace_back(operand);
127 if (operands == newOperands)
140 return operation && operation->
narguments() == narguments();
146 return "MemoryStateJoin";
149std::unique_ptr<rvsdg::Operation>
152 return std::make_unique<MemoryStateJoinOperation>(*
this);
155std::optional<std::vector<rvsdg::Output *>>
158 const std::vector<rvsdg::Output *> & operands)
160 if (operands.size() == 1)
161 return { { operands[0] } };
166std::optional<std::vector<rvsdg::Output *>>
169 const std::vector<rvsdg::Output *> & operands)
171 std::vector<rvsdg::Output *> newOperands;
173 for (
auto operand : operands)
178 seenOperands.
insert(operand);
179 newOperands.emplace_back(operand);
182 if (newOperands.size() == operands.size())
185 if (newOperands.size() == 1)
194std::optional<std::vector<rvsdg::Output *>>
197 const std::vector<rvsdg::Output *> & operands)
200 CollectNestedMemoryStateMergeOrJoinOperands<MemoryStateJoinOperation>(operands);
202 if (operands == newOperands)
205 const auto & memoryStateJoinNode =
CreateNode(std::move(newOperands));
206 return { { memoryStateJoinNode.output(0) } };
215 return operation && operation->
nresults() == nresults();
221 return "MemoryStateSplit";
224std::unique_ptr<rvsdg::Operation>
227 return std::make_unique<MemoryStateSplitOperation>(*
this);
230std::optional<std::vector<rvsdg::Output *>>
233 const std::vector<rvsdg::Output *> & operands)
243std::optional<std::vector<rvsdg::Output *>>
246 const std::vector<rvsdg::Output *> & operands)
249 const auto operand = operands[0];
251 auto [splitNode, splitOperation] =
256 const auto numResults = splitOperation->nresults() + operation.
nresults();
257 auto & newOperand = *splitNode->input(0)->origin();
258 auto results =
Create(newOperand, numResults);
260 for (
size_t n = 0; n < splitNode->noutputs(); n++)
262 const auto output = splitNode->output(n);
263 output->divert_users(results[n]);
266 return { { std::next(results.begin(), splitNode->noutputs()), results.end() } };
269std::optional<std::vector<rvsdg::Output *>>
272 const std::vector<rvsdg::Output *> & operands)
275 const auto operand = operands[0];
277 auto [mergeNode, mergeOperation] =
279 if (!mergeOperation || mergeOperation->narguments() != operation.
nresults())
289 { memoryNodeIds.begin(), memoryNodeIds.end() });
291 if (memoryNodeIdsSet.Size() != memoryNodeIds.size())
292 throw std::logic_error(
"Found duplicated memory node identifiers.");
296ToString(
const std::vector<MemoryNodeId> & memoryNodeIds)
299 for (
size_t n = 0; n < memoryNodeIds.size(); n++)
302 if (n != memoryNodeIds.size() - 1)
310 const std::vector<MemoryNodeId> & memoryNodeIds)
314 for (
size_t n = 0; n < memoryNodeIds.size(); n++)
326 return operation && operation->
nresults() == nresults()
327 && operation->memoryNodeIdToIndexMap_ == memoryNodeIdToIndexMap_;
336std::unique_ptr<rvsdg::Operation>
339 return std::make_unique<LambdaEntryMemoryStateSplitOperation>(*
this);
347 const auto operation =
354 if (!operation->memoryNodeIdToIndexMap_.HasKey(memoryNodeId))
360 return node.
output(index);
366 auto [_, operation] =
370 return operation->memoryNodeIdToIndexMap_.LookupValue(output.
index());
374 const std::vector<MemoryNodeId> & memoryNodeIds)
378 for (
size_t n = 0; n < memoryNodeIds.size(); n++)
399std::unique_ptr<rvsdg::Operation>
402 return std::make_unique<LambdaExitMemoryStateMergeOperation>(*
this);
410 const auto operation =
417 if (!operation->MemoryNodeIdToIndex_.HasKey(memoryNodeId))
424 return node.
input(index);
430 auto [_, operation] =
434 return operation->MemoryNodeIdToIndex_.LookupValue(input.
index());
437std::optional<std::vector<rvsdg::Output *>>
440 const std::vector<rvsdg::Output *> & operands)
442 if (operands.empty())
445 bool replacedOperands =
false;
446 std::vector<rvsdg::Output *> newOperands;
447 for (
auto operand : operands)
452 newOperands.push_back(operand);
459 newOperands.push_back(operand);
464 newOperands.push_back(newOperand);
465 replacedOperands =
true;
468 if (!replacedOperands)
476std::optional<std::vector<rvsdg::Output *>>
479 const std::vector<rvsdg::Output *> & operands)
481 if (operands.empty())
484 bool replacedOperands =
false;
485 std::vector<rvsdg::Output *> newOperands;
486 for (
auto operand : operands)
488 auto [storeNode, storeOperation] =
492 newOperands.push_back(operand);
499 newOperands.push_back(operand);
504 newOperands.push_back(newOperand);
505 replacedOperands =
true;
508 if (!replacedOperands)
516std::optional<std::vector<rvsdg::Output *>>
519 const std::vector<rvsdg::Output *> & operands)
521 if (operands.empty())
524 bool replacedOperands =
false;
525 std::vector<rvsdg::Output *> newOperands;
526 for (
auto operand : operands)
528 auto [allocaNode, allocaOperation] =
534 newOperands.push_back(newOperand);
535 replacedOperands =
true;
539 newOperands.push_back(operand);
543 if (!replacedOperands)
558 for (
size_t n = 0; n < memoryNodeIds.size(); n++)
560 MemoryNodeIdToIndex_.Insert(memoryNodeIds[n], n);
577std::unique_ptr<rvsdg::Operation>
580 return std::make_unique<CallEntryMemoryStateMergeOperation>(*
this);
588 const auto operation =
595 if (!operation->MemoryNodeIdToIndex_.HasKey(memoryNodeId))
602 return node.
input(index);
612 for (
size_t n = 0; n < memoryNodeIds.size(); n++)
614 memoryNodeIdToIndexMap_.Insert(memoryNodeIds[n], n);
631std::unique_ptr<rvsdg::Operation>
634 return std::make_unique<CallExitMemoryStateSplitOperation>(*
this);
642 const auto operation =
649 if (!operation->memoryNodeIdToIndexMap_.HasKey(memoryNodeId))
656 return node.
output(index);
662 auto [_, operation] =
666 return operation->memoryNodeIdToIndexMap_.LookupValue(output.
index());
672 for (
auto & input : node.
Inputs())
674 if (is<MemoryStateType>(input.Type()))
680 for (
auto & output : node.
Outputs())
682 if (is<MemoryStateType>(output.Type()))
std::string debug_string() const override
bool operator==(const Operation &other) const noexcept override
util::BijectiveMap< MemoryNodeId, size_t > MemoryNodeIdToIndex_
std::unique_ptr< Operation > copy() const override
std::vector< MemoryNodeId > getMemoryNodeIds() const noexcept
~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::string debug_string() const override
bool operator==(const Operation &other) const noexcept override
std::vector< MemoryNodeId > getMemoryNodeIds() const noexcept
util::BijectiveMap< MemoryNodeId, size_t > memoryNodeIdToIndexMap_
static rvsdg::Output * tryMapMemoryNodeIdToOutput(const rvsdg::SimpleNode &node, MemoryNodeId memoryNodeId)
~LambdaEntryMemoryStateSplitOperation() noexcept override
LambdaEntryMemoryStateSplitOperation(const std::vector< MemoryNodeId > &memoryNodeIds)
std::unique_ptr< Operation > copy() const override
std::vector< MemoryNodeId > getMemoryNodeIds() const noexcept
static MemoryNodeId mapOutputToMemoryNodeId(const rvsdg::Output &output)
std::string debug_string() const override
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 ®ion, const std::vector< rvsdg::Output * > &operands, const std::vector< MemoryNodeId > &memoryNodeIds)
static rvsdg::Input * tryMapMemoryNodeIdToInput(const rvsdg::SimpleNode &node, MemoryNodeId memoryNodeId)
LambdaExitMemoryStateMergeOperation(const std::vector< MemoryNodeId > &memoryNodeIds)
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::string debug_string() const override
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
static rvsdg::Input & MapMemoryStateOutputToInput(const rvsdg::Output &output)
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.
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.
~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.
std::string debug_string() const override
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
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
std::string debug_string() 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 std::shared_ptr< const MemoryStateType > Create()
static rvsdg::Input & MapMemoryStateOutputToInput(const rvsdg::Output &output)
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
static jlm::rvsdg::Output * Create(rvsdg::Region ®ion, std::shared_ptr< const jlm::rvsdg::Type > type)
OutputIteratorRange Outputs() noexcept
InputIteratorRange Inputs() noexcept
size_t ninputs() const noexcept
size_t noutputs() const noexcept
size_t index() const noexcept
const SimpleOperation & GetOperation() const noexcept override
NodeInput * input(size_t index) const noexcept
NodeOutput * output(size_t index) const noexcept
const std::shared_ptr< const rvsdg::Type > & result(size_t index) const noexcept
size_t nresults() const noexcept
size_t narguments() const noexcept
const V & LookupKey(const K &key) const
bool Insert(const K &key, const V &value)
bool insert(ItemType item)
std::size_t Size() const noexcept
IteratorRange< ItemConstIterator > Items() const noexcept
bool Contains(const ItemType &item) const noexcept
Global memory state passed between functions.
std::vector< rvsdg::Output * > CollectNestedMemoryStateMergeOrJoinOperands(const std::vector< rvsdg::Output * > &operands)
bool hasMemoryState(const rvsdg::Node &node)
static std::string ToString(const std::vector< MemoryNodeId > &memoryNodeIds)
static void CheckMemoryNodeIds(const std::vector< MemoryNodeId > &memoryNodeIds)
static std::vector< jlm::rvsdg::Output * > operands(const Node *node)
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
static std::string strfmt(Args... args)