Jlm
Loading...
Searching...
No Matches
MemoryStateOperations.cpp
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
11#include <jlm/util/HashSet.hpp>
12
13namespace jlm::llvm
14{
15
17
18bool
19MemoryStateMergeOperation::operator==(const Operation & other) const noexcept
20{
21 auto operation = dynamic_cast<const MemoryStateMergeOperation *>(&other);
22 return operation && operation->narguments() == narguments();
23}
24
25std::string
27{
28 return "MemoryStateMerge";
29}
30
31std::unique_ptr<rvsdg::Operation>
33{
34 return std::make_unique<MemoryStateMergeOperation>(*this);
35}
36
37std::optional<std::vector<rvsdg::Output *>>
40 const std::vector<rvsdg::Output *> & operands)
41{
42 if (operands.size() == 1)
43 return { { operands[0] } };
44
45 return std::nullopt;
46}
47
48std::optional<std::vector<rvsdg::Output *>>
51 const std::vector<rvsdg::Output *> & operands)
52{
53 const util::HashSet<rvsdg::Output *> uniqueOperands(operands.begin(), operands.end());
54
55 if (uniqueOperands.Size() == operands.size())
56 return std::nullopt;
57
58 auto result = Create(std::vector(uniqueOperands.Items().begin(), uniqueOperands.Items().end()));
59 return { { result } };
60}
61
62template<class TMemoryStateMergeOrJoinOperation>
63std::vector<rvsdg::Output *>
64CollectNestedMemoryStateMergeOrJoinOperands(const std::vector<rvsdg::Output *> & operands)
65{
66 static_assert(
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!");
70
71 std::vector<rvsdg::Output *> newOperands;
72 for (auto operand : operands)
73 {
74 auto [node, operation] =
76 if (operation)
77 {
78 auto nodeOperands =
79 CollectNestedMemoryStateMergeOrJoinOperands<TMemoryStateMergeOrJoinOperation>(
80 rvsdg::operands(node));
81 newOperands.insert(newOperands.end(), nodeOperands.begin(), nodeOperands.end());
82 }
83 else
84 {
85 newOperands.emplace_back(operand);
86 }
87 }
88
89 return newOperands;
90}
91
92std::optional<std::vector<rvsdg::Output *>>
95 const std::vector<rvsdg::Output *> & operands)
96{
97 auto newOperands =
98 CollectNestedMemoryStateMergeOrJoinOperands<MemoryStateMergeOperation>(operands);
99
100 if (operands == newOperands)
101 return std::nullopt;
102
103 auto result = Create(std::move(newOperands));
104 return { { result } };
105}
106
107std::optional<std::vector<rvsdg::Output *>>
110 const std::vector<rvsdg::Output *> & operands)
111{
112 std::vector<rvsdg::Output *> newOperands;
113 for (const auto operand : operands)
114 {
115 auto [splitNode, splitOperation] =
117 if (splitOperation)
118 {
119 newOperands.emplace_back(splitNode->input(0)->origin());
120 }
121 else
122 {
123 newOperands.emplace_back(operand);
124 }
125 }
126
127 if (operands == newOperands)
128 return std::nullopt;
129
130 auto result = Create(std::move(newOperands));
131 return { { result } };
132}
133
135
136bool
137MemoryStateJoinOperation::operator==(const Operation & other) const noexcept
138{
139 const auto operation = dynamic_cast<const MemoryStateMergeOperation *>(&other);
140 return operation && operation->narguments() == narguments();
141}
142
143std::string
145{
146 return "MemoryStateJoin";
147}
148
149std::unique_ptr<rvsdg::Operation>
151{
152 return std::make_unique<MemoryStateJoinOperation>(*this);
153}
154
155std::optional<std::vector<rvsdg::Output *>>
158 const std::vector<rvsdg::Output *> & operands)
159{
160 if (operands.size() == 1)
161 return { { operands[0] } };
162
163 return std::nullopt;
164}
165
166std::optional<std::vector<rvsdg::Output *>>
169 const std::vector<rvsdg::Output *> & operands)
170{
171 std::vector<rvsdg::Output *> newOperands;
173 for (auto operand : operands)
174 {
175 if (seenOperands.Contains(operand))
176 continue;
177
178 seenOperands.insert(operand);
179 newOperands.emplace_back(operand);
180 }
181
182 if (newOperands.size() == operands.size())
183 return std::nullopt;
184
185 if (newOperands.size() == 1)
186 {
187 // There is no need to create a join node if there is only a single operand.
188 return newOperands;
189 }
190
191 return { { CreateNode(newOperands).output(0) } };
192}
193
194std::optional<std::vector<rvsdg::Output *>>
197 const std::vector<rvsdg::Output *> & operands)
198{
199 auto newOperands =
200 CollectNestedMemoryStateMergeOrJoinOperands<MemoryStateJoinOperation>(operands);
201
202 if (operands == newOperands)
203 return std::nullopt;
204
205 const auto & memoryStateJoinNode = CreateNode(std::move(newOperands));
206 return { { memoryStateJoinNode.output(0) } };
207}
208
210
211bool
212MemoryStateSplitOperation::operator==(const Operation & other) const noexcept
213{
214 auto operation = dynamic_cast<const MemoryStateSplitOperation *>(&other);
215 return operation && operation->nresults() == nresults();
216}
217
218std::string
220{
221 return "MemoryStateSplit";
222}
223
224std::unique_ptr<rvsdg::Operation>
226{
227 return std::make_unique<MemoryStateSplitOperation>(*this);
228}
229
230std::optional<std::vector<rvsdg::Output *>>
232 const MemoryStateSplitOperation & operation,
233 const std::vector<rvsdg::Output *> & operands)
234{
235 JLM_ASSERT(operands.size() == 1);
236
237 if (operation.nresults() == 1)
238 return operands;
239
240 return std::nullopt;
241}
242
243std::optional<std::vector<rvsdg::Output *>>
245 const MemoryStateSplitOperation & operation,
246 const std::vector<rvsdg::Output *> & operands)
247{
248 JLM_ASSERT(operands.size() == 1);
249 const auto operand = operands[0];
250
251 auto [splitNode, splitOperation] =
253 if (!splitOperation)
254 return std::nullopt;
255
256 const auto numResults = splitOperation->nresults() + operation.nresults();
257 auto & newOperand = *splitNode->input(0)->origin();
258 auto results = Create(newOperand, numResults);
259
260 for (size_t n = 0; n < splitNode->noutputs(); n++)
261 {
262 const auto output = splitNode->output(n);
263 output->divert_users(results[n]);
264 }
265
266 return { { std::next(results.begin(), splitNode->noutputs()), results.end() } };
267}
268
269std::optional<std::vector<rvsdg::Output *>>
271 const MemoryStateSplitOperation & operation,
272 const std::vector<rvsdg::Output *> & operands)
273{
274 JLM_ASSERT(operands.size() == 1);
275 const auto operand = operands[0];
276
277 auto [mergeNode, mergeOperation] =
279 if (!mergeOperation || mergeOperation->narguments() != operation.nresults())
280 return std::nullopt;
281
282 return { rvsdg::operands(mergeNode) };
283}
284
285static void
286CheckMemoryNodeIds(const std::vector<MemoryNodeId> & memoryNodeIds)
287{
288 const util::HashSet<MemoryNodeId> memoryNodeIdsSet(
289 { memoryNodeIds.begin(), memoryNodeIds.end() });
290
291 if (memoryNodeIdsSet.Size() != memoryNodeIds.size())
292 throw std::logic_error("Found duplicated memory node identifiers.");
293}
294
295static std::string
296ToString(const std::vector<MemoryNodeId> & memoryNodeIds)
297{
298 std::string str;
299 for (size_t n = 0; n < memoryNodeIds.size(); n++)
300 {
301 str.append(util::strfmt(memoryNodeIds[n]));
302 if (n != memoryNodeIds.size() - 1)
303 str.append(", ");
304 }
305
306 return str;
307}
308
310 const std::vector<MemoryNodeId> & memoryNodeIds)
311 : MemoryStateOperation(1, memoryNodeIds.size())
312{
313 CheckMemoryNodeIds(memoryNodeIds);
314 for (size_t n = 0; n < memoryNodeIds.size(); n++)
315 {
316 memoryNodeIdToIndexMap_.Insert(memoryNodeIds[n], n);
317 }
318}
319
321
322bool
323LambdaEntryMemoryStateSplitOperation::operator==(const Operation & other) const noexcept
324{
325 const auto operation = dynamic_cast<const LambdaEntryMemoryStateSplitOperation *>(&other);
326 return operation && operation->nresults() == nresults()
327 && operation->memoryNodeIdToIndexMap_ == memoryNodeIdToIndexMap_;
328}
329
330std::string
332{
333 return util::strfmt("LambdaEntryMemoryStateSplit[", ToString(getMemoryNodeIds()), "]");
334}
335
336std::unique_ptr<rvsdg::Operation>
338{
339 return std::make_unique<LambdaEntryMemoryStateSplitOperation>(*this);
340}
341
344 const rvsdg::SimpleNode & node,
345 const MemoryNodeId memoryNodeId)
346{
347 const auto operation =
348 dynamic_cast<const LambdaEntryMemoryStateSplitOperation *>(&node.GetOperation());
349 if (!operation)
350 {
351 return nullptr;
352 }
353
354 if (!operation->memoryNodeIdToIndexMap_.HasKey(memoryNodeId))
355 {
356 return nullptr;
357 }
358
359 const auto index = operation->memoryNodeIdToIndexMap_.LookupKey(memoryNodeId);
360 return node.output(index);
361}
362
365{
366 auto [_, operation] =
368 JLM_ASSERT(operation != nullptr);
369
370 return operation->memoryNodeIdToIndexMap_.LookupValue(output.index());
371}
372
374 const std::vector<MemoryNodeId> & memoryNodeIds)
375 : MemoryStateOperation(memoryNodeIds.size(), 1)
376{
377 CheckMemoryNodeIds(memoryNodeIds);
378 for (size_t n = 0; n < memoryNodeIds.size(); n++)
379 {
380 MemoryNodeIdToIndex_.Insert(memoryNodeIds[n], n);
381 }
382}
383
385
386bool
387LambdaExitMemoryStateMergeOperation::operator==(const Operation & other) const noexcept
388{
389 const auto operation = dynamic_cast<const LambdaExitMemoryStateMergeOperation *>(&other);
390 return operation && operation->MemoryNodeIdToIndex_ == MemoryNodeIdToIndex_;
391}
392
393std::string
395{
396 return util::strfmt("LambdaExitMemoryStateMerge[", ToString(getMemoryNodeIds()), "]");
397}
398
399std::unique_ptr<rvsdg::Operation>
401{
402 return std::make_unique<LambdaExitMemoryStateMergeOperation>(*this);
403}
404
407 const rvsdg::SimpleNode & node,
408 const MemoryNodeId memoryNodeId)
409{
410 const auto operation =
411 dynamic_cast<const LambdaExitMemoryStateMergeOperation *>(&node.GetOperation());
412 if (!operation)
413 {
414 return nullptr;
415 }
416
417 if (!operation->MemoryNodeIdToIndex_.HasKey(memoryNodeId))
418 {
419 return nullptr;
420 }
421
422 const auto index = operation->MemoryNodeIdToIndex_.LookupKey(memoryNodeId);
423 JLM_ASSERT(index < node.ninputs());
424 return node.input(index);
425}
426
429{
430 auto [_, operation] =
432 JLM_ASSERT(operation != nullptr);
433
434 return operation->MemoryNodeIdToIndex_.LookupValue(input.index());
435}
436
437std::optional<std::vector<rvsdg::Output *>>
439 const LambdaExitMemoryStateMergeOperation & operation,
440 const std::vector<rvsdg::Output *> & operands)
441{
442 if (operands.empty())
443 return std::nullopt;
444
445 bool replacedOperands = false;
446 std::vector<rvsdg::Output *> newOperands;
447 for (auto operand : operands)
448 {
449 auto [loadNode, loadOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<LoadOperation>(*operand);
450 if (!loadOperation)
451 {
452 newOperands.push_back(operand);
453 continue;
454 }
455
456 auto loadAddress = LoadOperation::AddressInput(*loadNode).origin();
458 {
459 newOperands.push_back(operand);
460 continue;
461 }
462
463 auto newOperand = LoadOperation::MapMemoryStateOutputToInput(*operand).origin();
464 newOperands.push_back(newOperand);
465 replacedOperands = true;
466 }
467
468 if (!replacedOperands)
469 return std::nullopt;
470
471 return {
472 { CreateNode(*operands[0]->region(), newOperands, operation.getMemoryNodeIds()).output(0) }
473 };
474}
475
476std::optional<std::vector<rvsdg::Output *>>
478 const LambdaExitMemoryStateMergeOperation & operation,
479 const std::vector<rvsdg::Output *> & operands)
480{
481 if (operands.empty())
482 return std::nullopt;
483
484 bool replacedOperands = false;
485 std::vector<rvsdg::Output *> newOperands;
486 for (auto operand : operands)
487 {
488 auto [storeNode, storeOperation] =
490 if (!storeOperation)
491 {
492 newOperands.push_back(operand);
493 continue;
494 }
495
496 auto storeAddress = StoreOperation::AddressInput(*storeNode).origin();
498 {
499 newOperands.push_back(operand);
500 continue;
501 }
502
503 auto newOperand = StoreOperation::MapMemoryStateOutputToInput(*operand).origin();
504 newOperands.push_back(newOperand);
505 replacedOperands = true;
506 }
507
508 if (!replacedOperands)
509 return std::nullopt;
510
511 return {
512 { CreateNode(*operands[0]->region(), newOperands, operation.getMemoryNodeIds()).output(0) }
513 };
514}
515
516std::optional<std::vector<rvsdg::Output *>>
518 const LambdaExitMemoryStateMergeOperation & operation,
519 const std::vector<rvsdg::Output *> & operands)
520{
521 if (operands.empty())
522 return std::nullopt;
523
524 bool replacedOperands = false;
525 std::vector<rvsdg::Output *> newOperands;
526 for (auto operand : operands)
527 {
528 auto [allocaNode, allocaOperation] =
530 if (allocaOperation)
531 {
532 auto newOperand =
534 newOperands.push_back(newOperand);
535 replacedOperands = true;
536 }
537 else
538 {
539 newOperands.push_back(operand);
540 }
541 }
542
543 if (!replacedOperands)
544 return std::nullopt;
545
546 return {
547 { CreateNode(*operands[0]->region(), newOperands, operation.getMemoryNodeIds()).output(0) }
548 };
549}
550
552
554 const std::vector<MemoryNodeId> & memoryNodeIds)
555 : MemoryStateOperation(memoryNodeIds.size(), 1)
556{
557 CheckMemoryNodeIds(memoryNodeIds);
558 for (size_t n = 0; n < memoryNodeIds.size(); n++)
559 {
560 MemoryNodeIdToIndex_.Insert(memoryNodeIds[n], n);
561 }
562}
563
564bool
565CallEntryMemoryStateMergeOperation::operator==(const Operation & other) const noexcept
566{
567 const auto operation = dynamic_cast<const CallEntryMemoryStateMergeOperation *>(&other);
568 return operation && operation->MemoryNodeIdToIndex_ == MemoryNodeIdToIndex_;
569}
570
571std::string
573{
574 return util::strfmt("CallEntryMemoryStateMerge[", ToString(getMemoryNodeIds()), "]");
575}
576
577std::unique_ptr<rvsdg::Operation>
579{
580 return std::make_unique<CallEntryMemoryStateMergeOperation>(*this);
581}
582
585 const rvsdg::SimpleNode & node,
586 const MemoryNodeId memoryNodeId)
587{
588 const auto operation =
589 dynamic_cast<const CallEntryMemoryStateMergeOperation *>(&node.GetOperation());
590 if (!operation)
591 {
592 return nullptr;
593 }
594
595 if (!operation->MemoryNodeIdToIndex_.HasKey(memoryNodeId))
596 {
597 return nullptr;
598 }
599
600 const auto index = operation->MemoryNodeIdToIndex_.LookupKey(memoryNodeId);
601 JLM_ASSERT(index < node.ninputs());
602 return node.input(index);
603}
604
606
608 const std::vector<MemoryNodeId> & memoryNodeIds)
609 : MemoryStateOperation(1, memoryNodeIds.size())
610{
611 CheckMemoryNodeIds(memoryNodeIds);
612 for (size_t n = 0; n < memoryNodeIds.size(); n++)
613 {
614 memoryNodeIdToIndexMap_.Insert(memoryNodeIds[n], n);
615 }
616}
617
618bool
619CallExitMemoryStateSplitOperation::operator==(const Operation & other) const noexcept
620{
621 const auto operation = dynamic_cast<const CallExitMemoryStateSplitOperation *>(&other);
622 return operation && operation->memoryNodeIdToIndexMap_ == memoryNodeIdToIndexMap_;
623}
624
625std::string
627{
628 return util::strfmt("CallExitMemoryStateSplit[", ToString(getMemoryNodeIds()), "]");
629}
630
631std::unique_ptr<rvsdg::Operation>
633{
634 return std::make_unique<CallExitMemoryStateSplitOperation>(*this);
635}
636
639 const rvsdg::SimpleNode & node,
640 const MemoryNodeId memoryNodeId)
641{
642 const auto operation =
643 dynamic_cast<const CallExitMemoryStateSplitOperation *>(&node.GetOperation());
644 if (!operation)
645 {
646 return nullptr;
647 }
648
649 if (!operation->memoryNodeIdToIndexMap_.HasKey(memoryNodeId))
650 {
651 return nullptr;
652 }
653
654 const auto index = operation->memoryNodeIdToIndexMap_.LookupKey(memoryNodeId);
655 JLM_ASSERT(index < node.noutputs());
656 return node.output(index);
657}
658
661{
662 auto [_, operation] =
664 JLM_ASSERT(operation != nullptr);
665
666 return operation->memoryNodeIdToIndexMap_.LookupValue(output.index());
667}
668
669bool
671{
672 for (auto & input : node.Inputs())
673 {
674 if (is<MemoryStateType>(input.Type()))
675 {
676 return true;
677 }
678 }
679
680 for (auto & output : node.Outputs())
681 {
682 if (is<MemoryStateType>(output.Type()))
683 {
684 return true;
685 }
686 }
687
688 return false;
689}
690
691}
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)
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(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)
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)
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)
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
Definition Load.hpp:75
static rvsdg::Input & MapMemoryStateOutputToInput(const rvsdg::Output &output)
Definition Load.hpp:157
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
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()
Definition types.cpp:379
static rvsdg::Input & MapMemoryStateOutputToInput(const rvsdg::Output &output)
Definition Store.hpp:152
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
Definition Store.hpp:75
static jlm::rvsdg::Output * Create(rvsdg::Region &region, std::shared_ptr< const jlm::rvsdg::Type > type)
size_t index() const noexcept
Definition node.hpp:52
Output * origin() const noexcept
Definition node.hpp:58
OutputIteratorRange Outputs() noexcept
Definition node.hpp:657
InputIteratorRange Inputs() noexcept
Definition node.hpp:622
size_t ninputs() const noexcept
Definition node.hpp:609
size_t noutputs() const noexcept
Definition node.hpp:644
size_t index() const noexcept
Definition node.hpp:274
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
Definition operation.cpp:36
size_t nresults() const noexcept
Definition operation.cpp:30
size_t narguments() const noexcept
Definition operation.cpp:17
const V & LookupKey(const K &key) const
bool Insert(const K &key, const V &value)
bool insert(ItemType item)
Definition HashSet.hpp:210
std::size_t Size() const noexcept
Definition HashSet.hpp:187
IteratorRange< ItemConstIterator > Items() const noexcept
Definition HashSet.hpp:223
bool Contains(const ItemType &item) const noexcept
Definition HashSet.hpp:150
#define JLM_ASSERT(x)
Definition common.hpp:16
Global memory state passed between functions.
std::vector< rvsdg::Output * > CollectNestedMemoryStateMergeOrJoinOperands(const std::vector< rvsdg::Output * > &operands)
std::size_t MemoryNodeId
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)
Definition node.hpp:1049
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