Jlm
MemoryStateEncoder.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2021 Nico Reißmann <nico.reissmann@gmail.com>
3  * Copyright 2025 Håvard Krogstie <krogstie.havard@gmail.com>
4  * See COPYING for terms of redistribution.
5  */
6 
18 #include <jlm/rvsdg/gamma.hpp>
19 #include <jlm/rvsdg/MatchType.hpp>
20 #include <jlm/rvsdg/theta.hpp>
21 #include <jlm/rvsdg/traverser.hpp>
22 #include <jlm/util/Statistics.hpp>
23 
24 namespace jlm::llvm::aa
25 {
26 
31 {
32  // The number of entities that have been counted
33  uint64_t NumEntities = 0;
34 
35  // Count of total memory states, separated by MemoryNode type
36  uint64_t NumAllocas = 0;
37  uint64_t NumMallocs = 0;
38  uint64_t NumDeltas = 0;
39  uint64_t NumImports = 0;
40  uint64_t NumLambdas = 0;
41  uint64_t NumExternal = 0;
42 
43  // Among the MemoryNodes counted above, how many were not escaping
44  uint64_t NumNonEscaped = 0;
45 
46  // Remember the single entity with the highest number of memory states
47  uint64_t MaxMemoryStateEntity = 0;
48  // Do the same, but only include non-escaped MemoryNodes
50 
51  void
53  uint64_t numAllocas,
54  uint64_t numMallocs,
55  uint64_t numDeltas,
56  uint64_t numImports,
57  uint64_t numLambdas,
58  uint64_t numExternal,
59  uint64_t numNonEscaped)
60  {
61  NumEntities++;
62 
63  NumAllocas += numAllocas;
64  NumMallocs += numMallocs;
65  NumDeltas += numDeltas;
66  NumImports += numImports;
67  NumLambdas += numLambdas;
68  NumExternal += numExternal;
69 
70  const uint64_t totalMemoryStates =
71  numAllocas + numMallocs + numDeltas + numImports + numLambdas + numExternal;
72  if (totalMemoryStates > MaxMemoryStateEntity)
73  MaxMemoryStateEntity = totalMemoryStates;
74 
75  NumNonEscaped += numNonEscaped;
76  if (numNonEscaped > MaxNonEscapedMemoryStateEntity)
77  MaxNonEscapedMemoryStateEntity = numNonEscaped;
78  }
79 
80  void
82  const PointsToGraph & pointsToGraph,
84  {
85  uint64_t numAllocas = 0;
86  uint64_t numMallocs = 0;
87  uint64_t numDeltas = 0;
88  uint64_t numImports = 0;
89  uint64_t numLambdas = 0;
90  uint64_t numExternal = 0;
91 
92  uint64_t numNonEscaped = 0;
93 
94  for (const auto memoryNode : memoryNodes.Items())
95  {
96  if (!pointsToGraph.isExternallyAvailable(memoryNode))
97  numNonEscaped++;
98 
99  const auto kind = pointsToGraph.getNodeKind(memoryNode);
100  switch (kind)
101  {
103  numAllocas++;
104  break;
106  numDeltas++;
107  break;
109  numLambdas++;
110  break;
112  numImports++;
113  break;
115  numMallocs++;
116  break;
118  numExternal++;
119  break;
120  default:
121  throw std::logic_error("Unknown MemoryNode kind");
122  }
123  }
124 
125  CountEntity(
126  numAllocas,
127  numMallocs,
128  numDeltas,
129  numImports,
130  numLambdas,
131  numExternal,
132  numNonEscaped);
133  }
134 };
135 
140 {
141  // These are prefixes for statistics that count MemoryNode types
142  static constexpr auto NumTotalAllocaState_ = "#TotalAllocaState";
143  static constexpr auto NumTotalMallocState_ = "#TotalMallocState";
144  static constexpr auto NumTotalDeltaState_ = "#TotalDeltaState";
145  static constexpr auto NumTotalImportState_ = "#TotalImportState";
146  static constexpr auto NumTotalLambdaState_ = "#TotalLambdaState";
147  static constexpr auto NumTotalExternalState_ = "#TotalExternalState";
148  // Among all the MemoryNodes counted above, how many of them are not marked as escaped
149  static constexpr auto NumTotalNonEscapedState_ = "#TotalNonEscapedState";
150  static constexpr auto NumMaxMemoryState_ = "#MaxMemoryState";
151  static constexpr auto NumMaxNonEscapedMemoryState_ = "#MaxNonEscapedMemoryState";
152 
153  // The number of regions that are inside lambda nodes (including the lambda subregion itself)
154  static constexpr auto NumIntraProceduralRegions_ = "#IntraProceduralRegions";
155  // Suffix used when counting region state arguments (or LambdaEntrySplit for lambda subregions)
156  static constexpr auto RegionArgumentStateSuffix_ = "Arguments";
157 
158  // Counting both volatile and non-volatile loads
159  static constexpr auto NumLoadOperations_ = "#LoadOperations";
160  // Suffix used when counting memory states routed through loads
161  static constexpr auto LoadStateSuffix_ = "sThroughLoad";
162 
163  // Counting both volatile and non-volatile stores
164  static constexpr auto NumStoreOperations_ = "#StoreOperations";
165  // Suffix used when counting memory states routed through stores
166  static constexpr auto StoreStateSuffix_ = "sThroughStore";
167 
168  // Counting call entry merges
169  static constexpr auto NumCallEntryMergeOperations_ = "#CallEntryMergeOperations";
170  // Suffix used when counting memory states routed into call entry merges
171  static constexpr auto CallEntryMergeStateSuffix_ = "sIntoCallEntryMerge";
172 
173 public:
174  ~EncodingStatistics() override = default;
175 
176  explicit EncodingStatistics(const util::FilePath & sourceFile)
177  : Statistics(Statistics::Id::MemoryStateEncoder, sourceFile)
178  {}
179 
180  void
181  Start(const rvsdg::Graph & graph)
182  {
185  }
186 
187  void
189  {
191  }
192 
193  void
195  {
198  }
199 
200  void
202  {
205  }
206 
207  void
209  {
212  }
213 
214  void
216  {
219  }
220 
221  static std::unique_ptr<EncodingStatistics>
222  Create(const util::FilePath & sourceFile)
223  {
224  return std::make_unique<EncodingStatistics>(sourceFile);
225  }
226 
227 private:
228  void
229  AddMemoryStateTypeCounter(const std::string & suffix, const MemoryStateTypeCounter & counter)
230  {
233  AddMeasurement(NumTotalDeltaState_ + suffix, counter.NumDeltas);
238 
241  }
242 };
243 
246 class StateMap final
247 {
248 public:
253  {
254  friend StateMap;
255 
257  : MemoryNode_(memoryNode),
258  State_(&state)
259  {
260  JLM_ASSERT(is<MemoryStateType>(state.Type()));
261  }
262 
263  public:
264  [[nodiscard]] PointsToGraph::NodeIndex
265  MemoryNode() const noexcept
266  {
267  return MemoryNode_;
268  }
269 
270  [[nodiscard]] rvsdg::Output &
271  State() const noexcept
272  {
273  return *State_;
274  }
275 
276  void
277  ReplaceState(rvsdg::Output & state) noexcept
278  {
279  JLM_ASSERT(State_->region() == state.region());
280  JLM_ASSERT(is<MemoryStateType>(state.Type()));
281 
282  State_ = &state;
283  }
284 
285  static void
287  const std::vector<MemoryNodeStatePair *> & memoryNodeStatePairs,
288  const std::vector<rvsdg::Output *> & states)
289  {
290  JLM_ASSERT(memoryNodeStatePairs.size() == states.size());
291  for (size_t n = 0; n < memoryNodeStatePairs.size(); n++)
292  memoryNodeStatePairs[n]->ReplaceState(*states[n]);
293  }
294 
295  static void
297  const std::vector<MemoryNodeStatePair *> & memoryNodeStatePairs,
298  const rvsdg::Node::OutputIteratorRange & states)
299  {
300  auto it = states.begin();
301  for (auto memoryNodeStatePair : memoryNodeStatePairs)
302  {
303  memoryNodeStatePair->ReplaceState(*it);
304  it++;
305  }
306  JLM_ASSERT(it.GetOutput() == nullptr);
307  }
308 
309  static std::vector<rvsdg::Output *>
310  States(const std::vector<MemoryNodeStatePair *> & memoryNodeStatePairs)
311  {
312  std::vector<rvsdg::Output *> states;
313  for (auto & memoryNodeStatePair : memoryNodeStatePairs)
314  states.push_back(memoryNodeStatePair->State_);
315 
316  return states;
317  }
318 
319  private:
322  };
323 
324  StateMap() = default;
325 
326  StateMap(const StateMap &) = delete;
327 
328  StateMap(StateMap &&) = delete;
329 
330  StateMap &
331  operator=(const StateMap &) = delete;
332 
333  StateMap &
334  operator=(StateMap &&) = delete;
335 
338  {
339  if (const auto it = states_.find(memoryNode); it != states_.end())
340  return &it->second;
341 
342  return nullptr;
343  }
344 
345  const MemoryNodeStatePair *
346  TryGetState(PointsToGraph::NodeIndex memoryNode) const noexcept
347  {
348  return const_cast<StateMap *>(this)->TryGetState(memoryNode);
349  }
350 
351  bool
352  HasState(PointsToGraph::NodeIndex memoryNode) const noexcept
353  {
354  return TryGetState(memoryNode) != nullptr;
355  }
356 
357  MemoryNodeStatePair *
359  {
360  if (const auto statePair = TryGetState(memoryNode))
361  return statePair;
362  throw std::logic_error("Memory node does not have a state.");
363  }
364 
365  std::vector<MemoryNodeStatePair *>
367  {
368  std::vector<MemoryNodeStatePair *> memoryNodeStatePairs;
369  for (auto & memoryNode : memoryNodes.Items())
370  {
371  memoryNodeStatePairs.push_back(GetState(memoryNode));
372  }
373 
374  return memoryNodeStatePairs;
375  }
376 
384  std::vector<MemoryNodeStatePair *>
386  {
387  std::vector<MemoryNodeStatePair *> memoryNodeStatePairs;
388  for (auto & memoryNode : memoryNodes.Items())
389  {
390  if (const auto statePair = TryGetState(memoryNode))
391  memoryNodeStatePairs.push_back(statePair);
392  }
393 
394  return memoryNodeStatePairs;
395  }
396 
404  MemoryNodeStatePair *
406  {
407  auto [it, added] = states_.insert({ memoryNode, { memoryNode, state } });
408  if (!added)
409  throw std::logic_error("Memory node already has a state.");
410  return &it->second;
411  }
412 
413  static std::unique_ptr<StateMap>
415  {
416  return std::make_unique<StateMap>();
417  }
418 
419 private:
420  // std::unordered_map guarantees pointers to keys and values remain valid even when
421  // new pairs are added to the container.
422  std::unordered_map<PointsToGraph::NodeIndex, MemoryNodeStatePair> states_;
423 };
424 
428 {
429 public:
431  {
432  // Ensure that a PopRegion() was invoked for each invocation of a PushRegion().
433  JLM_ASSERT(StateMaps_.empty());
434  }
435 
436  explicit RegionalizedStateMap(const ModRefSummary & modRefSummary)
437  : ModRefSummary_(modRefSummary)
438  {}
439 
441 
443 
445  operator=(const RegionalizedStateMap &) = delete;
446 
449 
452  {
453  return GetStateMap(*state.region()).InsertState(memoryNode, state);
454  }
455 
457  TryGetState(const rvsdg::Region & region, PointsToGraph::NodeIndex memoryNode) const
458  {
459  return GetStateMap(region).TryGetState(memoryNode);
460  }
461 
462  bool
463  HasState(const rvsdg::Region & region, PointsToGraph::NodeIndex memoryNode) const
464  {
465  return GetStateMap(region).HasState(memoryNode);
466  }
467 
469  GetState(const rvsdg::Region & region, PointsToGraph::NodeIndex memoryNode)
470  {
471  return GetStateMap(region).GetState(memoryNode);
472  }
473 
474  std::vector<StateMap::MemoryNodeStatePair *>
476  const rvsdg::Region & region,
477  const util::HashSet<PointsToGraph::NodeIndex> & memoryNodes)
478  {
479  return GetStateMap(region).GetStates(memoryNodes);
480  }
481 
492  std::vector<StateMap::MemoryNodeStatePair *>
494  const rvsdg::Region & region,
495  const util::HashSet<PointsToGraph::NodeIndex> & memoryNodes) const
496  {
497  return GetStateMap(region).GetExistingStates(memoryNodes);
498  }
499 
500  std::vector<StateMap::MemoryNodeStatePair *>
502  {
503  return GetExistingStates(*node.region(), GetSimpleNodeModRef(node));
504  }
505 
508  {
509  return ModRefSummary_.GetSimpleNodeModRef(node);
510  }
511 
512  void
513  PushRegion(const rvsdg::Region & region)
514  {
515  JLM_ASSERT(StateMaps_.find(&region) == StateMaps_.end());
516  StateMaps_[&region] = StateMap::Create();
517  }
518 
519  void
520  PopRegion(const rvsdg::Region & region)
521  {
522  JLM_ASSERT(StateMaps_.find(&region) != StateMaps_.end());
523  StateMaps_.erase(&region);
524  }
525 
526 private:
527  StateMap &
528  GetStateMap(const rvsdg::Region & region) const noexcept
529  {
530  JLM_ASSERT(StateMaps_.find(&region) != StateMaps_.end());
531  return *StateMaps_.at(&region);
532  }
533 
535 
536  std::unordered_map<const rvsdg::Region *, std::unique_ptr<StateMap>> StateMaps_;
537 };
538 
542 {
543 public:
544  explicit Context(const ModRefSummary & modRefSummary)
545  : RegionalizedStateMap_(modRefSummary),
546  ModRefSummary_(modRefSummary)
547  {}
548 
549  Context(const Context &) = delete;
550 
551  Context(Context &&) = delete;
552 
553  Context &
554  operator=(const Context &) = delete;
555 
556  Context &
557  operator=(Context &&) = delete;
558 
561  {
562  return RegionalizedStateMap_;
563  }
564 
565  const ModRefSummary &
566  GetModRefSummary() const noexcept
567  {
568  return ModRefSummary_;
569  }
570 
573  {
575  }
576 
579  {
580  return LoadCounter_;
581  }
582 
585  {
586  return StoreCounter_;
587  }
588 
591  {
592  return CallEntryMergeCounter_;
593  }
594 
595  static std::unique_ptr<MemoryStateEncoder::Context>
596  Create(const ModRefSummary & modRefSummary)
597  {
598  return std::make_unique<Context>(modRefSummary);
599  }
600 
601 private:
604 
605  // Counters used for producing statistics about memory states
610 };
611 
612 static std::vector<MemoryNodeId>
614 {
615  std::vector<MemoryNodeId> memoryNodeIds;
616  for (const auto memoryNode : memoryNodes.Items())
617  {
618  memoryNodeIds.push_back(memoryNode);
619  }
620 
621  return memoryNodeIds;
622 }
623 
624 MemoryStateEncoder::~MemoryStateEncoder() noexcept = default;
625 
626 MemoryStateEncoder::MemoryStateEncoder() = default;
627 
628 void
630  rvsdg::RvsdgModule & rvsdgModule,
631  const ModRefSummary & modRefSummary,
632  util::StatisticsCollector & statisticsCollector)
633 {
634  Context_ = Context::Create(modRefSummary);
635  auto statistics = EncodingStatistics::Create(rvsdgModule.SourceFilePath().value());
636 
637  statistics->Start(rvsdgModule.Rvsdg());
638  EncodeRegion(rvsdgModule.Rvsdg().GetRootRegion());
639  statistics->Stop();
640 
641  statistics->AddIntraProceduralRegionMemoryStateCounts(
642  Context_->GetInterProceduralRegionCounter());
643  statistics->AddLoadMemoryStateCounts(Context_->GetLoadCounter());
644  statistics->AddStoreMemoryStateCounts(Context_->GetStoreCounter());
645  statistics->AddCallEntryMergeStateCounts(Context_->GetCallEntryMergeCounter());
646 
647  statisticsCollector.CollectDemandedStatistics(std::move(statistics));
648 
649  // Discard internal state to free up memory after we are done with the encoding
650  Context_.reset();
651 
652  // Remove all nodes that became dead throughout the encoding.
653  DeadNodeElimination deadNodeElimination;
654  deadNodeElimination.Run(rvsdgModule, statisticsCollector);
655 }
656 
657 void
659 {
660  using namespace jlm::rvsdg;
661 
662  TopDownTraverser traverser(&region);
663  for (const auto node : traverser)
664  {
666  *node,
667  [&](SimpleNode & simpleNode)
668  {
669  EncodeSimpleNode(simpleNode);
670  },
671  [&](StructuralNode & structuralNode)
672  {
673  EncodeStructuralNode(structuralNode);
674  });
675  }
676 }
677 
678 void
680 {
681  if (auto lambdaNode = dynamic_cast<const rvsdg::LambdaNode *>(&structuralNode))
682  {
683  EncodeLambda(*lambdaNode);
684  }
685  else if (auto deltaNode = dynamic_cast<const rvsdg::DeltaNode *>(&structuralNode))
686  {
687  EncodeDelta(*deltaNode);
688  }
689  else if (auto phiNode = dynamic_cast<const rvsdg::PhiNode *>(&structuralNode))
690  {
691  EncodePhi(*phiNode);
692  }
693  else if (auto gammaNode = dynamic_cast<rvsdg::GammaNode *>(&structuralNode))
694  {
695  EncodeGamma(*gammaNode);
696  }
697  else if (auto thetaNode = dynamic_cast<rvsdg::ThetaNode *>(&structuralNode))
698  {
699  EncodeTheta(*thetaNode);
700  }
701  else
702  {
703  JLM_UNREACHABLE("Unhandled node type.");
704  }
705 }
706 
707 void
709 {
711  simpleNode.GetOperation(),
712  [&](const AllocaOperation &)
713  {
714  EncodeAlloca(simpleNode);
715  },
716  [&](const MallocOperation &)
717  {
718  EncodeMalloc(simpleNode);
719  },
720  [&](const LoadOperation &)
721  {
722  EncodeLoad(simpleNode);
723  },
724  [&](const StoreOperation &)
725  {
726  EncodeStore(simpleNode);
727  },
728  [&](const CallOperation &)
729  {
730  EncodeCall(simpleNode);
731  },
732  [&](const FreeOperation &)
733  {
734  EncodeFree(simpleNode);
735  },
736  [&](const MemCpyOperation &)
737  {
738  EncodeMemcpy(simpleNode);
739  },
740  [&](const MemSetOperation &)
741  {
742  EncodeMemset(simpleNode);
743  },
744  [&](const MemoryStateOperation &)
745  {
746  // Nothing needs to be done
747  },
748  [&]()
749  {
750  // Ensure we took care of all memory state consuming/producing nodes
751  JLM_ASSERT(!hasMemoryState(simpleNode));
752  });
753 }
754 
755 void
757 {
758  JLM_ASSERT(is<AllocaOperation>(allocaNode.GetOperation()));
759 
760  auto & stateMap = Context_->GetRegionalizedStateMap();
761  auto allocaMemoryNodes = stateMap.GetSimpleNodeModRef(allocaNode);
762  JLM_ASSERT(allocaMemoryNodes.Size() == 1);
763  auto allocaMemoryNode = *allocaMemoryNodes.Items().begin();
764  auto & allocaNodeStateOutput = *allocaNode.output(1);
765 
766  // If a state representing the alloca already exists in the region,
767  // merge it with the state created by the alloca using a MemoryStateJoin node.
768  if (const auto statePair = stateMap.TryGetState(*allocaNode.region(), allocaMemoryNode))
769  {
770  auto & joinNode =
771  MemoryStateJoinOperation::CreateNode({ &allocaNodeStateOutput, &statePair->State() });
772  auto & joinOutput = *joinNode.output(0);
773  statePair->ReplaceState(joinOutput);
774  }
775  else
776  {
777  stateMap.InsertState(allocaMemoryNode, allocaNodeStateOutput);
778  }
779 }
780 
781 void
783 {
784  JLM_ASSERT(is<MallocOperation>(mallocNode.GetOperation()));
785  auto & stateMap = Context_->GetRegionalizedStateMap();
786  auto mallocMemoryNodes = stateMap.GetSimpleNodeModRef(mallocNode);
787  JLM_ASSERT(mallocMemoryNodes.Size() == 1);
788  auto mallocMemoryNode = *mallocMemoryNodes.Items().begin();
789 
790  auto & mallocNodeStateOutput = MallocOperation::memoryStateOutput(mallocNode);
791 
792  // We use a static heap model. This means that multiple invocations of an malloc
793  // at runtime can refer to the same abstract memory location. We therefore need to
794  // merge the previous and the current state to ensure that the previous state
795  // is not just simply replaced and therefore "lost".
796  if (const auto statePair = stateMap.TryGetState(*mallocNode.region(), mallocMemoryNode))
797  {
798  auto & joinNode =
799  MemoryStateJoinOperation::CreateNode({ &mallocNodeStateOutput, &statePair->State() });
800  auto & joinOutput = *joinNode.output(0);
801  statePair->ReplaceState(joinOutput);
802  }
803  else
804  {
805  stateMap.InsertState(mallocMemoryNode, mallocNodeStateOutput);
806  }
807 }
808 
809 void
811 {
812  JLM_ASSERT(is<LoadOperation>(node.GetOperation()));
813  auto & stateMap = Context_->GetRegionalizedStateMap();
814 
815  const auto & memoryNodes = stateMap.GetSimpleNodeModRef(node);
816  Context_->GetLoadCounter().CountEntity(
817  Context_->GetModRefSummary().GetPointsToGraph(),
818  memoryNodes);
819 
820  const auto memoryNodeStatePairs = stateMap.GetExistingStates(*node.region(), memoryNodes);
821  const auto memoryStates = StateMap::MemoryNodeStatePair::States(memoryNodeStatePairs);
822 
823  const auto & newLoadNode = ReplaceLoadNode(node, memoryStates);
824 
826  memoryNodeStatePairs,
827  LoadOperation::MemoryStateOutputs(newLoadNode));
828 }
829 
830 void
832 {
833  auto & stateMap = Context_->GetRegionalizedStateMap();
834 
835  const auto & memoryNodes = stateMap.GetSimpleNodeModRef(node);
836  Context_->GetStoreCounter().CountEntity(
837  Context_->GetModRefSummary().GetPointsToGraph(),
838  memoryNodes);
839 
840  const auto memoryNodeStatePairs = stateMap.GetExistingStates(*node.region(), memoryNodes);
841  const auto memoryStates = StateMap::MemoryNodeStatePair::States(memoryNodeStatePairs);
842 
843  const auto & newStoreNode = ReplaceStoreNode(node, memoryStates);
844 
846  memoryNodeStatePairs,
847  StoreOperation::MemoryStateOutputs(newStoreNode));
848 }
849 
850 void
852 {
853  JLM_ASSERT(is<FreeOperation>(freeNode.GetOperation()));
854  auto & stateMap = Context_->GetRegionalizedStateMap();
855 
856  auto address = freeNode.input(0)->origin();
857  auto ioState = freeNode.input(freeNode.ninputs() - 1)->origin();
858  auto memoryNodeStatePairs = stateMap.GetExistingStates(freeNode);
859  auto inStates = StateMap::MemoryNodeStatePair::States(memoryNodeStatePairs);
860 
861  auto outputs = FreeOperation::Create(address, inStates, ioState);
862 
863  // Redirect IO state edge
864  freeNode.output(freeNode.noutputs() - 1)->divert_users(outputs.back());
865 
867  memoryNodeStatePairs,
868  { outputs.begin(), std::prev(outputs.end()) });
869 }
870 
871 void
873 {
874  const auto region = callNode.region();
875  auto & regionalizedStateMap = Context_->GetRegionalizedStateMap();
876 
877  const auto & memoryNodes = regionalizedStateMap.GetSimpleNodeModRef(callNode);
878  Context_->GetCallEntryMergeCounter().CountEntity(
879  Context_->GetModRefSummary().GetPointsToGraph(),
880  memoryNodes);
881 
882  const auto statePairs = regionalizedStateMap.GetExistingStates(*region, memoryNodes);
883 
884  std::vector<rvsdg::Output *> inputStates;
885  std::vector<MemoryNodeId> memoryNodeIds;
886  for (auto statePair : statePairs)
887  {
888  inputStates.emplace_back(&statePair->State());
889  memoryNodeIds.push_back(statePair->MemoryNode());
890  }
891 
892  auto & entryMergeNode =
893  CallEntryMemoryStateMergeOperation::CreateNode(*region, inputStates, memoryNodeIds);
894  CallOperation::GetMemoryStateInput(callNode).divert_to(entryMergeNode.output(0));
895 
896  auto & exitSplitNode = CallExitMemoryStateSplitOperation::CreateNode(
898  memoryNodeIds);
899 
901 }
902 
903 void
905 {
906  JLM_ASSERT(is<MemCpyOperation>(memcpyNode.GetOperation()));
907  auto & stateMap = Context_->GetRegionalizedStateMap();
908 
909  auto memoryNodeStatePairs = stateMap.GetExistingStates(memcpyNode);
910  auto memoryStateOperands = StateMap::MemoryNodeStatePair::States(memoryNodeStatePairs);
911 
912  auto memoryStateResults = ReplaceMemcpyNode(memcpyNode, memoryStateOperands);
913 
914  StateMap::MemoryNodeStatePair::ReplaceStates(memoryNodeStatePairs, memoryStateResults);
915 }
916 
917 void
919 {
920  JLM_ASSERT(is<MemSetOperation>(memsetNode.GetOperation()));
921  auto & stateMap = Context_->GetRegionalizedStateMap();
922 
923  auto memoryNodeStatePairs = stateMap.GetExistingStates(memsetNode);
924  auto memoryStateOperands = StateMap::MemoryNodeStatePair::States(memoryNodeStatePairs);
925 
926  auto memoryStateResults = ReplaceMemsetNode(memsetNode, memoryStateOperands);
927 
928  StateMap::MemoryNodeStatePair::ReplaceStates(memoryNodeStatePairs, memoryStateResults);
929 }
930 
931 void
933 {
934  EncodeLambdaEntry(lambdaNode);
935  EncodeRegion(*lambdaNode.subregion());
936  EncodeLambdaExit(lambdaNode);
937 }
938 
939 void
941 {
942  auto & memoryStateArgument = GetMemoryStateRegionArgument(lambdaNode);
943 
944  const auto & memoryNodes = Context_->GetModRefSummary().GetLambdaEntryModRef(lambdaNode);
945  Context_->GetInterProceduralRegionCounter().CountEntity(
946  Context_->GetModRefSummary().GetPointsToGraph(),
947  memoryNodes);
948 
949  const auto memoryNodeIds = GetMemoryNodeIds(memoryNodes);
950  auto & stateMap = Context_->GetRegionalizedStateMap();
951 
952  stateMap.PushRegion(*lambdaNode.subregion());
953  auto & lambdaEntrySplitNode =
954  LambdaEntryMemoryStateSplitOperation::CreateNode(memoryStateArgument, memoryNodeIds);
955  const auto states = rvsdg::outputs(&lambdaEntrySplitNode);
956 
957  size_t n = 0;
958  for (auto & memoryNode : memoryNodes.Items())
959  stateMap.InsertState(memoryNode, *states[n++]);
960 
961  if (!states.empty())
962  {
963  // This additional MemoryStateMergeOperation node makes all other nodes in the function that
964  // consume the memory state dependent on this node and therefore transitively on the
965  // LambdaEntryMemoryStateSplitOperation. This ensures that the
966  // LambdaEntryMemoryStateSplitOperation is always visited before all other memory state
967  // consuming nodes:
968  //
969  // ... := LAMBDA[f]
970  // [..., a1, ...]
971  // o1, ..., ox := LambdaEntryMemoryStateSplit a1
972  // oy = MemoryStateMerge o1, ..., ox
973  // ....
974  //
975  // No other memory state consuming node aside from the LambdaEntryMemoryStateSplitOperation
976  // should now consume a1.
977  auto state = MemoryStateMergeOperation::Create(states);
978  memoryStateArgument.divertUsersWhere(
979  *state,
980  [&lambdaEntrySplitNode](const rvsdg::Input & user)
981  {
982  return rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(user) != &lambdaEntrySplitNode;
983  });
984  }
985 }
986 
987 void
989 {
990  const auto & memoryNodes = Context_->GetModRefSummary().GetLambdaExitModRef(lambdaNode);
991  auto & stateMap = Context_->GetRegionalizedStateMap();
992  auto & memoryStateResult = GetMemoryStateRegionResult(lambdaNode);
993 
994  std::vector<rvsdg::Output *> states;
995  std::vector<MemoryNodeId> memoryNodeIds;
996  auto & subregion = *lambdaNode.subregion();
997  const auto memoryNodeStatePairs = stateMap.GetStates(subregion, memoryNodes);
998  for (const auto memoryNodeStatePair : memoryNodeStatePairs)
999  {
1000  states.push_back(&memoryNodeStatePair->State());
1001  memoryNodeIds.push_back(memoryNodeStatePair->MemoryNode());
1002  }
1003 
1004  const auto mergedState =
1005  LambdaExitMemoryStateMergeOperation::CreateNode(subregion, states, memoryNodeIds).output(0);
1006  memoryStateResult.divert_to(mergedState);
1007 
1008  stateMap.PopRegion(*lambdaNode.subregion());
1009 }
1010 
1011 void
1013 {
1014  EncodeRegion(*phiNode.subregion());
1015 }
1016 
1017 void
1019 {
1020  // Nothing needs to be done
1021 }
1022 
1023 void
1025 {
1026  for (auto & subregion : gammaNode.Subregions())
1027  Context_->GetRegionalizedStateMap().PushRegion(subregion);
1028 
1029  EncodeGammaEntry(gammaNode);
1030 
1031  for (auto & subregion : gammaNode.Subregions())
1032  EncodeRegion(subregion);
1033 
1034  EncodeGammaExit(gammaNode);
1035 
1036  for (auto & subregion : gammaNode.Subregions())
1037  Context_->GetRegionalizedStateMap().PopRegion(subregion);
1038 }
1039 
1040 void
1042 {
1043  auto region = gammaNode.region();
1044  auto & stateMap = Context_->GetRegionalizedStateMap();
1045  auto memoryNodes = Context_->GetModRefSummary().GetGammaEntryModRef(gammaNode);
1046 
1047  // Count the memory state arguments once per subregion
1048  for ([[maybe_unused]] auto & subregion : gammaNode.Subregions())
1049  Context_->GetInterProceduralRegionCounter().CountEntity(
1050  Context_->GetModRefSummary().GetPointsToGraph(),
1051  memoryNodes);
1052 
1053  auto memoryNodeStatePairs = stateMap.GetExistingStates(*region, memoryNodes);
1054  for (auto & memoryNodeStatePair : memoryNodeStatePairs)
1055  {
1056  auto gammaInput = gammaNode.AddEntryVar(&memoryNodeStatePair->State());
1057  for (auto & argument : gammaInput.branchArgument)
1058  stateMap.InsertState(memoryNodeStatePair->MemoryNode(), *argument);
1059  }
1060 }
1061 
1062 void
1064 {
1065  auto & stateMap = Context_->GetRegionalizedStateMap();
1066  auto memoryNodes = Context_->GetModRefSummary().GetGammaExitModRef(gammaNode);
1067  auto memoryNodeStatePairs = stateMap.GetExistingStates(*gammaNode.region(), memoryNodes);
1068 
1069  for (auto & memoryNodeStatePair : memoryNodeStatePairs)
1070  {
1071  std::vector<rvsdg::Output *> states;
1072 
1073  for (auto & subregion : gammaNode.Subregions())
1074  {
1075  auto & state = stateMap.GetState(subregion, memoryNodeStatePair->MemoryNode())->State();
1076  states.push_back(&state);
1077  }
1078 
1079  auto state = gammaNode.AddExitVar(states).output;
1080  memoryNodeStatePair->ReplaceState(*state);
1081  }
1082 }
1083 
1084 void
1086 {
1087  Context_->GetRegionalizedStateMap().PushRegion(*thetaNode.subregion());
1088 
1089  auto thetaStateOutputs = EncodeThetaEntry(thetaNode);
1090  EncodeRegion(*thetaNode.subregion());
1091  EncodeThetaExit(thetaNode, thetaStateOutputs);
1092 
1093  Context_->GetRegionalizedStateMap().PopRegion(*thetaNode.subregion());
1094 }
1095 
1096 std::vector<rvsdg::Output *>
1098 {
1099  auto region = thetaNode.region();
1100  auto & stateMap = Context_->GetRegionalizedStateMap();
1101  const auto & memoryNodes = Context_->GetModRefSummary().GetThetaModRef(thetaNode);
1102  Context_->GetInterProceduralRegionCounter().CountEntity(
1103  Context_->GetModRefSummary().GetPointsToGraph(),
1104  memoryNodes);
1105 
1106  std::vector<rvsdg::Output *> thetaStateOutputs;
1107  auto memoryNodeStatePairs = stateMap.GetExistingStates(*region, memoryNodes);
1108  for (auto & memoryNodeStatePair : memoryNodeStatePairs)
1109  {
1110  auto loopvar = thetaNode.AddLoopVar(&memoryNodeStatePair->State());
1111  stateMap.InsertState(memoryNodeStatePair->MemoryNode(), *loopvar.pre);
1112  thetaStateOutputs.push_back(loopvar.output);
1113  }
1114 
1115  return thetaStateOutputs;
1116 }
1117 
1118 void
1120  rvsdg::ThetaNode & thetaNode,
1121  const std::vector<rvsdg::Output *> & thetaStateOutputs)
1122 {
1123  auto subregion = thetaNode.subregion();
1124  auto & stateMap = Context_->GetRegionalizedStateMap();
1125  const auto & memoryNodes = Context_->GetModRefSummary().GetThetaModRef(thetaNode);
1126  auto memoryNodeStatePairs = stateMap.GetExistingStates(*thetaNode.region(), memoryNodes);
1127 
1128  JLM_ASSERT(memoryNodeStatePairs.size() == thetaStateOutputs.size());
1129  for (size_t n = 0; n < thetaStateOutputs.size(); n++)
1130  {
1131  auto thetaStateOutput = thetaStateOutputs[n];
1132  auto & memoryNodeStatePair = memoryNodeStatePairs[n];
1133  auto memoryNode = memoryNodeStatePair->MemoryNode();
1134  auto loopvar = thetaNode.MapOutputLoopVar(*thetaStateOutput);
1135  JLM_ASSERT(loopvar.input->origin() == &memoryNodeStatePair->State());
1136 
1137  auto & subregionState = stateMap.GetState(*subregion, memoryNode)->State();
1138  loopvar.post->divert_to(&subregionState);
1139  memoryNodeStatePair->ReplaceState(*thetaStateOutput);
1140  }
1141 }
1142 
1145  const rvsdg::SimpleNode & node,
1146  const std::vector<rvsdg::Output *> & memoryStates)
1147 {
1148  JLM_ASSERT(is<LoadOperation>(node.GetOperation()));
1149 
1150  if (const auto loadVolatileOperation =
1151  dynamic_cast<const LoadVolatileOperation *>(&node.GetOperation()))
1152  {
1153  auto & newLoadNode = LoadVolatileOperation::CreateNode(
1154  *LoadOperation::AddressInput(node).origin(),
1155  *LoadVolatileOperation::IOStateInput(node).origin(),
1156  memoryStates,
1157  loadVolatileOperation->GetLoadedType(),
1158  loadVolatileOperation->GetAlignment());
1159  auto & oldLoadedValueOutput = LoadOperation::LoadedValueOutput(node);
1160  auto & newLoadedValueOutput = LoadOperation::LoadedValueOutput(newLoadNode);
1161  auto & oldIOStateOutput = LoadVolatileOperation::IOStateOutput(node);
1162  auto & newIOStateOutput = LoadVolatileOperation::IOStateOutput(newLoadNode);
1163  oldLoadedValueOutput.divert_users(&newLoadedValueOutput);
1164  oldIOStateOutput.divert_users(&newIOStateOutput);
1165  return newLoadNode;
1166  }
1167 
1168  if (const auto loadNonVolatileOperation =
1169  dynamic_cast<const LoadNonVolatileOperation *>(&node.GetOperation()))
1170  {
1171  auto & newLoadNode = LoadNonVolatileOperation::CreateNode(
1172  *LoadOperation::AddressInput(node).origin(),
1173  memoryStates,
1174  loadNonVolatileOperation->GetLoadedType(),
1175  loadNonVolatileOperation->GetAlignment());
1176  auto & oldLoadedValueOutput = LoadOperation::LoadedValueOutput(node);
1177  auto & newLoadedValueOutput = LoadNonVolatileOperation::LoadedValueOutput(newLoadNode);
1178  oldLoadedValueOutput.divert_users(&newLoadedValueOutput);
1179  return newLoadNode;
1180  }
1181 
1182  JLM_UNREACHABLE("Unhandled load node type.");
1183 }
1184 
1187  const rvsdg::SimpleNode & node,
1188  const std::vector<rvsdg::Output *> & memoryStates)
1189 {
1190  if (const auto oldStoreVolatileOperation =
1191  dynamic_cast<const StoreVolatileOperation *>(&node.GetOperation()))
1192  {
1193  auto & newStoreNode = StoreVolatileOperation::CreateNode(
1194  *StoreOperation::AddressInput(node).origin(),
1195  *StoreOperation::StoredValueInput(node).origin(),
1196  *StoreVolatileOperation::IOStateInput(node).origin(),
1197  memoryStates,
1198  oldStoreVolatileOperation->GetAlignment());
1199  auto & oldIOStateOutput = StoreVolatileOperation::IOStateOutput(node);
1200  auto & newIOStateOutput = StoreVolatileOperation::IOStateOutput(newStoreNode);
1201  oldIOStateOutput.divert_users(&newIOStateOutput);
1202  return newStoreNode;
1203  }
1204 
1205  if (const auto oldStoreNonVolatileOperation =
1206  dynamic_cast<const StoreNonVolatileOperation *>(&node.GetOperation()))
1207  {
1209  *StoreOperation::AddressInput(node).origin(),
1210  *StoreOperation::StoredValueInput(node).origin(),
1211  memoryStates,
1212  oldStoreNonVolatileOperation->GetAlignment());
1213  }
1214 
1215  JLM_UNREACHABLE("Unhandled store node type.");
1216 }
1217 
1218 std::vector<rvsdg::Output *>
1220  const rvsdg::SimpleNode & memcpyNode,
1221  const std::vector<rvsdg::Output *> & memoryStates)
1222 {
1223  JLM_ASSERT(is<MemCpyOperation>(memcpyNode.GetOperation()));
1224 
1225  auto destination = memcpyNode.input(0)->origin();
1226  auto source = memcpyNode.input(1)->origin();
1227  auto length = memcpyNode.input(2)->origin();
1228 
1229  if (is<MemCpyVolatileOperation>(memcpyNode.GetOperation()))
1230  {
1231  auto & ioState = *memcpyNode.input(3)->origin();
1232  auto & newMemcpyNode =
1233  MemCpyVolatileOperation::CreateNode(*destination, *source, *length, ioState, memoryStates);
1234  auto results = rvsdg::outputs(&newMemcpyNode);
1235 
1236  // Redirect I/O state
1237  memcpyNode.output(0)->divert_users(results[0]);
1238 
1239  // Skip I/O state and only return memory states
1240  return { std::next(results.begin()), results.end() };
1241  }
1242  if (is<MemCpyNonVolatileOperation>(memcpyNode.GetOperation()))
1243  {
1244  return MemCpyNonVolatileOperation::create(destination, source, length, memoryStates);
1245  }
1246 
1247  throw std::logic_error("Unhandled memcpy operation type.");
1248 }
1249 
1250 std::vector<rvsdg::Output *>
1252  const rvsdg::SimpleNode & memsetNode,
1253  const std::vector<rvsdg::Output *> & memoryStates)
1254 {
1255  JLM_ASSERT(is<MemSetOperation>(memsetNode.GetOperation()));
1256 
1257  auto destination = MemSetOperation::destinationInput(memsetNode).origin();
1258  auto value = MemSetOperation::valueInput(memsetNode).origin();
1259  auto length = MemSetOperation::lengthInput(memsetNode).origin();
1260 
1261  if (is<MemSetNonVolatileOperation>(memsetNode.GetOperation()))
1262  {
1263  return outputs(
1264  &MemSetNonVolatileOperation::createNode(*destination, *value, *length, memoryStates));
1265  }
1266 
1267  throw std::logic_error("Unhandled memset operation type.");
1268 }
1269 
1270 }
static jlm::util::StatisticsCollector statisticsCollector
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
Call operation class.
Definition: call.hpp:251
static rvsdg::Input & GetMemoryStateInput(const rvsdg::Node &node) noexcept
Definition: call.hpp:357
static rvsdg::Output & GetMemoryStateOutput(const rvsdg::Node &node) noexcept
Definition: call.hpp:369
Dead Node Elimination Optimization.
void Run(rvsdg::RvsdgModule &module, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *pointer, const std::vector< const Variable * > &memoryStates, const Variable *iOState)
Definition: operators.hpp:2558
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands, const std::vector< MemoryNodeId > &memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< LoadNonVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
Definition: Load.hpp:466
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
Definition: Load.hpp:75
static rvsdg::Output & LoadedValueOutput(const rvsdg::Node &node)
Definition: Load.hpp:84
static rvsdg::Node::OutputIteratorRange MemoryStateOutputs(const rvsdg::Node &node) noexcept
Definition: Load.hpp:116
static rvsdg::Input & IOStateInput(const rvsdg::Node &node) noexcept
Definition: Load.hpp:225
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< LoadVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
Definition: Load.cpp:388
static rvsdg::Output & IOStateOutput(const rvsdg::Node &node)
Definition: Load.hpp:234
static rvsdg::Output & memoryStateOutput(const rvsdg::Node &node)
Definition: operators.hpp:2476
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *destination, const Variable *source, const Variable *length, const std::vector< const Variable * > &memoryStates)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &destination, rvsdg::Output &source, rvsdg::Output &length, rvsdg::Output &ioState, const std::vector< rvsdg::Output * > &memoryStates)
static rvsdg::SimpleNode & createNode(rvsdg::Output &destination, rvsdg::Output &value, rvsdg::Output &length, const std::vector< rvsdg::Output * > &memoryStates)
static rvsdg::Input & destinationInput(const rvsdg::Node &node) noexcept
static rvsdg::Input & lengthInput(const rvsdg::Node &node) noexcept
static rvsdg::Input & valueInput(const rvsdg::Node &node) noexcept
static rvsdg::SimpleNode & CreateNode(const std::vector< rvsdg::Output * > &operands)
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &operands)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
Definition: Store.hpp:323
static rvsdg::Input & StoredValueInput(const rvsdg::Node &node) noexcept
Definition: Store.hpp:84
static rvsdg::Node::OutputIteratorRange MemoryStateOutputs(const rvsdg::Node &node) noexcept
Definition: Store.hpp:93
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
Definition: Store.hpp:75
static rvsdg::Output & IOStateOutput(const rvsdg::Node &node) noexcept
Definition: Store.hpp:430
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< StoreVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition: Store.hpp:453
static rvsdg::Input & IOStateInput(const rvsdg::Node &node) noexcept
Definition: Store.hpp:421
Statistics class for memory state encoder encoding.
static std::unique_ptr< EncodingStatistics > Create(const util::FilePath &sourceFile)
void AddStoreMemoryStateCounts(const MemoryStateTypeCounter &counter)
static constexpr auto NumIntraProceduralRegions_
void AddCallEntryMergeStateCounts(const MemoryStateTypeCounter &counter)
static constexpr auto NumTotalMallocState_
static constexpr auto NumTotalAllocaState_
void AddLoadMemoryStateCounts(const MemoryStateTypeCounter &counter)
static constexpr auto NumCallEntryMergeOperations_
static constexpr auto RegionArgumentStateSuffix_
static constexpr auto NumTotalNonEscapedState_
static constexpr auto NumTotalExternalState_
void AddMemoryStateTypeCounter(const std::string &suffix, const MemoryStateTypeCounter &counter)
void AddIntraProceduralRegionMemoryStateCounts(const MemoryStateTypeCounter &counter)
static constexpr auto CallEntryMergeStateSuffix_
EncodingStatistics(const util::FilePath &sourceFile)
static constexpr auto NumMaxNonEscapedMemoryState_
~EncodingStatistics() override=default
static constexpr auto NumTotalImportState_
static constexpr auto NumTotalLambdaState_
void Start(const rvsdg::Graph &graph)
Context for the memory state encoder.
Context(const ModRefSummary &modRefSummary)
static std::unique_ptr< MemoryStateEncoder::Context > Create(const ModRefSummary &modRefSummary)
Context & operator=(const Context &)=delete
MemoryStateTypeCounter & GetCallEntryMergeCounter()
const ModRefSummary & GetModRefSummary() const noexcept
MemoryStateTypeCounter & GetInterProceduralRegionCounter()
RegionalizedStateMap & GetRegionalizedStateMap() noexcept
Context & operator=(Context &&)=delete
static std::vector< rvsdg::Output * > ReplaceMemcpyNode(const rvsdg::SimpleNode &memcpyNode, const std::vector< rvsdg::Output * > &memoryStates)
void EncodeMalloc(const rvsdg::SimpleNode &mallocNode)
void EncodeCall(const rvsdg::SimpleNode &callNode)
void EncodeLambdaEntry(const rvsdg::LambdaNode &lambdaNode)
void EncodeAlloca(const rvsdg::SimpleNode &allocaNode)
static rvsdg::SimpleNode & ReplaceStoreNode(const rvsdg::SimpleNode &node, const std::vector< rvsdg::Output * > &memoryStates)
void EncodeStructuralNode(rvsdg::StructuralNode &structuralNode)
void EncodeDelta(const rvsdg::DeltaNode &deltaNode)
void EncodeLambda(const rvsdg::LambdaNode &lambda)
void EncodeLoad(const rvsdg::SimpleNode &node)
void EncodeGammaExit(rvsdg::GammaNode &gammaNode)
void EncodeStore(const rvsdg::SimpleNode &node)
std::unique_ptr< Context > Context_
void EncodeGammaEntry(rvsdg::GammaNode &gammaNode)
void EncodeRegion(rvsdg::Region &region)
static rvsdg::SimpleNode & ReplaceLoadNode(const rvsdg::SimpleNode &node, const std::vector< rvsdg::Output * > &memoryStates)
void EncodeSimpleNode(const rvsdg::SimpleNode &simpleNode)
std::vector< rvsdg::Output * > EncodeThetaEntry(rvsdg::ThetaNode &thetaNode)
void EncodePhi(const rvsdg::PhiNode &phiNode)
static std::vector< rvsdg::Output * > ReplaceMemsetNode(const rvsdg::SimpleNode &memsetNode, const std::vector< rvsdg::Output * > &memoryStates)
void EncodeMemcpy(const rvsdg::SimpleNode &memcpyNode)
void EncodeGamma(rvsdg::GammaNode &gammaNode)
void EncodeFree(const rvsdg::SimpleNode &freeNode)
void EncodeMemset(const rvsdg::SimpleNode &memsetNode)
void EncodeLambdaExit(const rvsdg::LambdaNode &lambdaNode)
void EncodeThetaExit(rvsdg::ThetaNode &thetaNode, const std::vector< rvsdg::Output * > &thetaStateOutputs)
void EncodeTheta(rvsdg::ThetaNode &thetaNode)
virtual const util::HashSet< PointsToGraph::NodeIndex > & GetSimpleNodeModRef(const rvsdg::SimpleNode &node) const =0
bool isExternallyAvailable(NodeIndex index) const
NodeKind getNodeKind(NodeIndex index) const
Hash map for mapping Rvsdg regions to StateMap class instances.
std::unordered_map< const rvsdg::Region *, std::unique_ptr< StateMap > > StateMaps_
StateMap::MemoryNodeStatePair * GetState(const rvsdg::Region &region, PointsToGraph::NodeIndex memoryNode)
void PushRegion(const rvsdg::Region &region)
bool HasState(const rvsdg::Region &region, PointsToGraph::NodeIndex memoryNode) const
std::vector< StateMap::MemoryNodeStatePair * > GetExistingStates(const rvsdg::SimpleNode &node) const
StateMap::MemoryNodeStatePair * InsertState(PointsToGraph::NodeIndex memoryNode, rvsdg::Output &state)
RegionalizedStateMap(RegionalizedStateMap &&)=delete
RegionalizedStateMap(const ModRefSummary &modRefSummary)
RegionalizedStateMap & operator=(RegionalizedStateMap &&)=delete
std::vector< StateMap::MemoryNodeStatePair * > GetExistingStates(const rvsdg::Region &region, const util::HashSet< PointsToGraph::NodeIndex > &memoryNodes) const
const util::HashSet< PointsToGraph::NodeIndex > & GetSimpleNodeModRef(const rvsdg::SimpleNode &node) const
RegionalizedStateMap(const RegionalizedStateMap &)=delete
StateMap::MemoryNodeStatePair * TryGetState(const rvsdg::Region &region, PointsToGraph::NodeIndex memoryNode) const
RegionalizedStateMap & operator=(const RegionalizedStateMap &)=delete
std::vector< StateMap::MemoryNodeStatePair * > GetStates(const rvsdg::Region &region, const util::HashSet< PointsToGraph::NodeIndex > &memoryNodes)
void PopRegion(const rvsdg::Region &region)
StateMap & GetStateMap(const rvsdg::Region &region) const noexcept
static void ReplaceStates(const std::vector< MemoryNodeStatePair * > &memoryNodeStatePairs, const rvsdg::Node::OutputIteratorRange &states)
static void ReplaceStates(const std::vector< MemoryNodeStatePair * > &memoryNodeStatePairs, const std::vector< rvsdg::Output * > &states)
void ReplaceState(rvsdg::Output &state) noexcept
static std::vector< rvsdg::Output * > States(const std::vector< MemoryNodeStatePair * > &memoryNodeStatePairs)
MemoryNodeStatePair(PointsToGraph::NodeIndex memoryNode, rvsdg::Output &state)
PointsToGraph::NodeIndex MemoryNode() const noexcept
Hash map for mapping points-to graph memory nodes to RVSDG memory states.
std::unordered_map< PointsToGraph::NodeIndex, MemoryNodeStatePair > states_
std::vector< MemoryNodeStatePair * > GetExistingStates(const util::HashSet< PointsToGraph::NodeIndex > &memoryNodes)
StateMap & operator=(StateMap &&)=delete
MemoryNodeStatePair * GetState(PointsToGraph::NodeIndex memoryNode)
StateMap(const StateMap &)=delete
MemoryNodeStatePair * InsertState(PointsToGraph::NodeIndex memoryNode, rvsdg::Output &state)
std::vector< MemoryNodeStatePair * > GetStates(const util::HashSet< PointsToGraph::NodeIndex > &memoryNodes)
bool HasState(PointsToGraph::NodeIndex memoryNode) const noexcept
static std::unique_ptr< StateMap > Create()
StateMap & operator=(const StateMap &)=delete
MemoryNodeStatePair * TryGetState(PointsToGraph::NodeIndex memoryNode) noexcept
StateMap(StateMap &&)=delete
const MemoryNodeStatePair * TryGetState(PointsToGraph::NodeIndex memoryNode) const noexcept
Delta node.
Definition: delta.hpp:129
Conditional operator / pattern matching.
Definition: gamma.hpp:99
EntryVar AddEntryVar(rvsdg::Output *origin)
Routes a variable into the gamma branches.
Definition: gamma.cpp:260
ExitVar AddExitVar(const std::vector< rvsdg::Output * > &values)
Routes per-branch result of gamma to output.
Definition: gamma.cpp:362
Region & GetRootRegion() const noexcept
Definition: graph.hpp:99
void divert_to(Output *new_origin)
Definition: node.cpp:64
Output * origin() const noexcept
Definition: node.hpp:58
Lambda node.
Definition: lambda.hpp:83
rvsdg::Region * subregion() const noexcept
Definition: lambda.hpp:138
rvsdg::Region * region() const noexcept
Definition: node.hpp:761
size_t ninputs() const noexcept
Definition: node.hpp:609
size_t noutputs() const noexcept
Definition: node.hpp:644
rvsdg::Region * region() const noexcept
Definition: node.cpp:151
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition: node.hpp:366
void divert_users(jlm::rvsdg::Output *new_origin)
Definition: node.hpp:301
A phi node represents the fixpoint of mutually recursive definitions.
Definition: Phi.hpp:46
rvsdg::Region * subregion() const noexcept
Definition: Phi.hpp:320
Represent acyclic RVSDG subgraphs.
Definition: region.hpp:213
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
SubregionIteratorRange Subregions()
LoopVar MapOutputLoopVar(const rvsdg::Output &output) const
Maps variable at exit to full varibale description.
Definition: theta.cpp:166
rvsdg::Region * subregion() const noexcept
Definition: theta.hpp:79
LoopVar AddLoopVar(rvsdg::Output *origin)
Creates a new loop-carried variable.
Definition: theta.cpp:49
IteratorRange< ItemConstIterator > Items() const noexcept
Definition: HashSet.hpp:223
void CollectDemandedStatistics(std::unique_ptr< Statistics > statistics)
Definition: Statistics.hpp:574
Statistics Interface.
Definition: Statistics.hpp:31
util::Timer & GetTimer(const std::string &name)
Definition: Statistics.cpp:137
Statistics(const Statistics::Id &statisticsId, util::FilePath sourceFile)
Definition: Statistics.hpp:76
util::Timer & AddTimer(std::string name)
Definition: Statistics.cpp:158
void AddMeasurement(std::string name, T value)
Definition: Statistics.hpp:177
void start() noexcept
Definition: time.hpp:54
void stop() noexcept
Definition: time.hpp:67
#define JLM_ASSERT(x)
Definition: common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition: common.hpp:43
static std::vector< MemoryNodeId > GetMemoryNodeIds(const util::HashSet< PointsToGraph::NodeIndex > &memoryNodes)
rvsdg::Input & GetMemoryStateRegionResult(const rvsdg::LambdaNode &lambdaNode) noexcept
rvsdg::Output & GetMemoryStateRegionArgument(const rvsdg::LambdaNode &lambdaNode) noexcept
void MatchTypeWithDefault(T &obj, const Fns &... fns)
Pattern match over subclass type of given object with default handler.
void MatchTypeOrFail(T &obj, const Fns &... fns)
Pattern match over subclass type of given object.
size_t nnodes(const jlm::rvsdg::Region *region) noexcept
Definition: region.cpp:785
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)
Definition: node.hpp:1058
Helper struct for counting up MemoryNodes, among some set of entities that use them.
void CountEntity(const PointsToGraph &pointsToGraph, util::HashSet< PointsToGraph::NodeIndex > memoryNodes)
void CountEntity(uint64_t numAllocas, uint64_t numMallocs, uint64_t numDeltas, uint64_t numImports, uint64_t numLambdas, uint64_t numExternal, uint64_t numNonEscaped)
rvsdg::Output * output
Output of gamma.
Definition: gamma.hpp:154
static const char * NumRvsdgNodesBefore
Definition: Statistics.hpp:214
static const char * Timer
Definition: Statistics.hpp:251