Jlm
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 
13 namespace jlm::llvm
14 {
15 
17 
18 bool
19 MemoryStateMergeOperation::operator==(const Operation & other) const noexcept
20 {
21  auto operation = dynamic_cast<const MemoryStateMergeOperation *>(&other);
22  return operation && operation->narguments() == narguments();
23 }
24 
25 std::string
27 {
28  return "MemoryStateMerge";
29 }
30 
31 std::unique_ptr<rvsdg::Operation>
33 {
34  return std::make_unique<MemoryStateMergeOperation>(*this);
35 }
36 
37 std::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 
48 std::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 
62 template<class TMemoryStateMergeOrJoinOperation>
63 std::vector<rvsdg::Output *>
64 CollectNestedMemoryStateMergeOrJoinOperands(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] =
75  rvsdg::TryGetSimpleNodeAndOptionalOp<TMemoryStateMergeOrJoinOperation>(*operand);
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 
92 std::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 
107 std::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] =
116  rvsdg::TryGetSimpleNodeAndOptionalOp<MemoryStateSplitOperation>(*operand);
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 
136 bool
137 MemoryStateJoinOperation::operator==(const Operation & other) const noexcept
138 {
139  const auto operation = dynamic_cast<const MemoryStateMergeOperation *>(&other);
140  return operation && operation->narguments() == narguments();
141 }
142 
143 std::string
145 {
146  return "MemoryStateJoin";
147 }
148 
149 std::unique_ptr<rvsdg::Operation>
151 {
152  return std::make_unique<MemoryStateJoinOperation>(*this);
153 }
154 
155 std::optional<std::vector<rvsdg::Output *>>
157  const MemoryStateJoinOperation &,
158  const std::vector<rvsdg::Output *> & operands)
159 {
160  if (operands.size() == 1)
161  return { { operands[0] } };
162 
163  return std::nullopt;
164 }
165 
166 std::optional<std::vector<rvsdg::Output *>>
168  const MemoryStateJoinOperation &,
169  const std::vector<rvsdg::Output *> & operands)
170 {
171  std::vector<rvsdg::Output *> newOperands;
172  util::HashSet<rvsdg::Output *> seenOperands;
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 
194 std::optional<std::vector<rvsdg::Output *>>
196  const MemoryStateJoinOperation &,
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 
211 bool
212 MemoryStateSplitOperation::operator==(const Operation & other) const noexcept
213 {
214  auto operation = dynamic_cast<const MemoryStateSplitOperation *>(&other);
215  return operation && operation->nresults() == nresults();
216 }
217 
218 std::string
220 {
221  return "MemoryStateSplit";
222 }
223 
224 std::unique_ptr<rvsdg::Operation>
226 {
227  return std::make_unique<MemoryStateSplitOperation>(*this);
228 }
229 
230 std::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 
243 std::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] =
252  rvsdg::TryGetSimpleNodeAndOptionalOp<MemoryStateSplitOperation>(*operand);
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 
269 std::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] =
278  rvsdg::TryGetSimpleNodeAndOptionalOp<MemoryStateMergeOperation>(*operand);
279  if (!mergeOperation || mergeOperation->narguments() != operation.nresults())
280  return std::nullopt;
281 
282  return { rvsdg::operands(mergeNode) };
283 }
284 
285 static void
286 CheckMemoryNodeIds(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 
295 static std::string
296 ToString(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 
322 bool
323 LambdaEntryMemoryStateSplitOperation::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 
330 std::string
332 {
333  return util::strfmt("LambdaEntryMemoryStateSplit[", ToString(getMemoryNodeIds()), "]");
334 }
335 
336 std::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] =
367  rvsdg::TryGetSimpleNodeAndOptionalOp<LambdaEntryMemoryStateSplitOperation>(output);
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 
386 bool
387 LambdaExitMemoryStateMergeOperation::operator==(const Operation & other) const noexcept
388 {
389  const auto operation = dynamic_cast<const LambdaExitMemoryStateMergeOperation *>(&other);
390  return operation && operation->MemoryNodeIdToIndex_ == MemoryNodeIdToIndex_;
391 }
392 
393 std::string
395 {
396  return util::strfmt("LambdaExitMemoryStateMerge[", ToString(getMemoryNodeIds()), "]");
397 }
398 
399 std::unique_ptr<rvsdg::Operation>
401 {
402  return std::make_unique<LambdaExitMemoryStateMergeOperation>(*this);
403 }
404 
405 rvsdg::Input *
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] =
431  rvsdg::TryGetSimpleNodeAndOptionalOp<LambdaExitMemoryStateMergeOperation>(input);
432  JLM_ASSERT(operation != nullptr);
433 
434  return operation->MemoryNodeIdToIndex_.LookupValue(input.index());
435 }
436 
437 std::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();
457  if (!rvsdg::IsOwnerNodeOperation<AllocaOperation>(*loadAddress))
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 
476 std::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] =
489  rvsdg::TryGetSimpleNodeAndOptionalOp<StoreOperation>(*operand);
490  if (!storeOperation)
491  {
492  newOperands.push_back(operand);
493  continue;
494  }
495 
496  auto storeAddress = StoreOperation::AddressInput(*storeNode).origin();
497  if (!rvsdg::IsOwnerNodeOperation<AllocaOperation>(*storeAddress))
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 
516 std::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] =
529  rvsdg::TryGetSimpleNodeAndOptionalOp<AllocaOperation>(*operand);
530  if (allocaOperation)
531  {
532  auto newOperand =
533  UndefValueOperation::Create(*allocaNode->region(), MemoryStateType::Create());
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 
564 bool
565 CallEntryMemoryStateMergeOperation::operator==(const Operation & other) const noexcept
566 {
567  const auto operation = dynamic_cast<const CallEntryMemoryStateMergeOperation *>(&other);
568  return operation && operation->MemoryNodeIdToIndex_ == MemoryNodeIdToIndex_;
569 }
570 
571 std::string
573 {
574  return util::strfmt("CallEntryMemoryStateMerge[", ToString(getMemoryNodeIds()), "]");
575 }
576 
577 std::unique_ptr<rvsdg::Operation>
579 {
580  return std::make_unique<CallEntryMemoryStateMergeOperation>(*this);
581 }
582 
583 rvsdg::Input *
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 
618 bool
619 CallExitMemoryStateSplitOperation::operator==(const Operation & other) const noexcept
620 {
621  const auto operation = dynamic_cast<const CallExitMemoryStateSplitOperation *>(&other);
622  return operation && operation->memoryNodeIdToIndexMap_ == memoryNodeIdToIndexMap_;
623 }
624 
625 std::string
627 {
628  return util::strfmt("CallExitMemoryStateSplit[", ToString(getMemoryNodeIds()), "]");
629 }
630 
631 std::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] =
663  rvsdg::TryGetSimpleNodeAndOptionalOp<CallExitMemoryStateSplitOperation>(output);
664  JLM_ASSERT(operation != nullptr);
665 
666  return operation->memoryNodeIdToIndexMap_.LookupValue(output.index());
667 }
668 
669 bool
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
~CallEntryMemoryStateMergeOperation() noexcept override
std::vector< MemoryNodeId > getMemoryNodeIds() const noexcept
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)
std::vector< MemoryNodeId > getMemoryNodeIds() const noexcept
LambdaEntryMemoryStateSplitOperation(const std::vector< MemoryNodeId > &memoryNodeIds)
std::unique_ptr< Operation > copy() const override
static MemoryNodeId mapOutputToMemoryNodeId(const rvsdg::Output &output)
static std::optional< std::vector< rvsdg::Output * > > NormalizeLoadFromAlloca(const LambdaExitMemoryStateMergeOperation &operation, const std::vector< rvsdg::Output * > &operands)
std::vector< MemoryNodeId > getMemoryNodeIds() const noexcept
static std::optional< std::vector< rvsdg::Output * > > NormalizeStoreToAlloca(const LambdaExitMemoryStateMergeOperation &operation, const std::vector< rvsdg::Output * > &operands)
util::BijectiveMap< MemoryNodeId, size_t > MemoryNodeIdToIndex_
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
static rvsdg::SimpleNode & CreateNode(const std::vector< rvsdg::Output * > &operands)
~MemoryStateJoinOperation() noexcept override
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::Output * Create(const std::vector< rvsdg::Output * > &operands)
~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 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()
Definition: types.cpp:379
static rvsdg::Input & MapMemoryStateOutputToInput(const rvsdg::Output &output)
Definition: Store.hpp:134
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)
Definition: operators.hpp:1055
Output * origin() const noexcept
Definition: node.hpp:58
size_t index() const noexcept
Definition: node.hpp:52
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
Definition: simple-node.cpp:48
NodeInput * input(size_t index) const noexcept
Definition: simple-node.hpp:82
NodeOutput * output(size_t index) const noexcept
Definition: simple-node.hpp:88
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
bool Contains(const ItemType &item) const noexcept
Definition: HashSet.hpp:150
IteratorRange< ItemConstIterator > Items() const noexcept
Definition: HashSet.hpp:223
#define JLM_ASSERT(x)
Definition: common.hpp:16
Global memory state passed between functions.
std::size_t MemoryNodeId
bool hasMemoryState(const rvsdg::Node &node)
std::vector< rvsdg::Output * > CollectNestedMemoryStateMergeOrJoinOperands(const std::vector< rvsdg::Output * > &operands)
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
static std::string strfmt(Args... args)
Definition: strfmt.hpp:35