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 
13 #include <jlm/rvsdg/gamma.hpp>
14 #include <jlm/rvsdg/MatchType.hpp>
15 #include <jlm/rvsdg/theta.hpp>
16 #include <jlm/rvsdg/traverser.hpp>
17 #include <jlm/util/Statistics.hpp>
18 
19 namespace jlm::llvm::aa
20 {
21 
26 {
27  // The number of entities that have been counted
28  uint64_t NumEntities = 0;
29 
30  // Count of total memory states, separated by MemoryNode type
31  uint64_t NumAllocas = 0;
32  uint64_t NumMallocs = 0;
33  uint64_t NumDeltas = 0;
34  uint64_t NumImports = 0;
35  uint64_t NumLambdas = 0;
36  uint64_t NumExternal = 0;
37 
38  // Among the MemoryNodes counted above, how many were not escaping
39  uint64_t NumNonEscaped = 0;
40 
41  // Remember the single entity with the highest number of memory states
42  uint64_t MaxMemoryStateEntity = 0;
43  // Do the same, but only include non-escaped MemoryNodes
45 
46  void
48  uint64_t numAllocas,
49  uint64_t numMallocs,
50  uint64_t numDeltas,
51  uint64_t numImports,
52  uint64_t numLambdas,
53  uint64_t numExternal,
54  uint64_t numNonEscaped)
55  {
56  NumEntities++;
57 
58  NumAllocas += numAllocas;
59  NumMallocs += numMallocs;
60  NumDeltas += numDeltas;
61  NumImports += numImports;
62  NumLambdas += numLambdas;
63  NumExternal += numExternal;
64 
65  const uint64_t totalMemoryStates =
66  numAllocas + numMallocs + numDeltas + numImports + numLambdas + numExternal;
67  if (totalMemoryStates > MaxMemoryStateEntity)
68  MaxMemoryStateEntity = totalMemoryStates;
69 
70  NumNonEscaped += numNonEscaped;
71  if (numNonEscaped > MaxNonEscapedMemoryStateEntity)
72  MaxNonEscapedMemoryStateEntity = numNonEscaped;
73  }
74 
75  void
77  const PointsToGraph & pointsToGraph,
79  {
80  uint64_t numAllocas = 0;
81  uint64_t numMallocs = 0;
82  uint64_t numDeltas = 0;
83  uint64_t numImports = 0;
84  uint64_t numLambdas = 0;
85  uint64_t numExternal = 0;
86 
87  uint64_t numNonEscaped = 0;
88 
89  for (const auto memoryNode : memoryNodes.Items())
90  {
91  if (!pointsToGraph.isExternallyAvailable(memoryNode))
92  numNonEscaped++;
93 
94  const auto kind = pointsToGraph.getNodeKind(memoryNode);
95  switch (kind)
96  {
98  numAllocas++;
99  break;
101  numDeltas++;
102  break;
104  numLambdas++;
105  break;
107  numImports++;
108  break;
110  numMallocs++;
111  break;
113  numExternal++;
114  break;
115  default:
116  throw std::logic_error("Unknown MemoryNode kind");
117  }
118  }
119 
120  CountEntity(
121  numAllocas,
122  numMallocs,
123  numDeltas,
124  numImports,
125  numLambdas,
126  numExternal,
127  numNonEscaped);
128  }
129 };
130 
135 {
136  // These are prefixes for statistics that count MemoryNode types
137  static constexpr auto NumTotalAllocaState_ = "#TotalAllocaState";
138  static constexpr auto NumTotalMallocState_ = "#TotalMallocState";
139  static constexpr auto NumTotalDeltaState_ = "#TotalDeltaState";
140  static constexpr auto NumTotalImportState_ = "#TotalImportState";
141  static constexpr auto NumTotalLambdaState_ = "#TotalLambdaState";
142  static constexpr auto NumTotalExternalState_ = "#TotalExternalState";
143  // Among all the MemoryNodes counted above, how many of them are not marked as escaped
144  static constexpr auto NumTotalNonEscapedState_ = "#TotalNonEscapedState";
145  static constexpr auto NumMaxMemoryState_ = "#MaxMemoryState";
146  static constexpr auto NumMaxNonEscapedMemoryState_ = "#MaxNonEscapedMemoryState";
147 
148  // The number of regions that are inside lambda nodes (including the lambda subregion itself)
149  static constexpr auto NumIntraProceduralRegions_ = "#IntraProceduralRegions";
150  // Suffix used when counting region state arguments (or LambdaEntrySplit for lambda subregions)
151  static constexpr auto RegionArgumentStateSuffix_ = "Arguments";
152 
153  // Counting both volatile and non-volatile loads
154  static constexpr auto NumLoadOperations_ = "#LoadOperations";
155  // Suffix used when counting memory states routed through loads
156  static constexpr auto LoadStateSuffix_ = "sThroughLoad";
157 
158  // Counting both volatile and non-volatile stores
159  static constexpr auto NumStoreOperations_ = "#StoreOperations";
160  // Suffix used when counting memory states routed through stores
161  static constexpr auto StoreStateSuffix_ = "sThroughStore";
162 
163  // Counting call entry merges
164  static constexpr auto NumCallEntryMergeOperations_ = "#CallEntryMergeOperations";
165  // Suffix used when counting memory states routed into call entry merges
166  static constexpr auto CallEntryMergeStateSuffix_ = "sIntoCallEntryMerge";
167 
168 public:
169  ~EncodingStatistics() override = default;
170 
171  explicit EncodingStatistics(const util::FilePath & sourceFile)
172  : Statistics(Statistics::Id::MemoryStateEncoder, sourceFile)
173  {}
174 
175  void
176  Start(const rvsdg::Graph & graph)
177  {
180  }
181 
182  void
184  {
186  }
187 
188  void
190  {
193  }
194 
195  void
197  {
200  }
201 
202  void
204  {
207  }
208 
209  void
211  {
214  }
215 
216  static std::unique_ptr<EncodingStatistics>
217  Create(const util::FilePath & sourceFile)
218  {
219  return std::make_unique<EncodingStatistics>(sourceFile);
220  }
221 
222 private:
223  void
224  AddMemoryStateTypeCounter(const std::string & suffix, const MemoryStateTypeCounter & counter)
225  {
228  AddMeasurement(NumTotalDeltaState_ + suffix, counter.NumDeltas);
233 
236  }
237 };
238 
241 class StateMap final
242 {
243 public:
248  {
249  friend StateMap;
250 
252  : MemoryNode_(memoryNode),
253  State_(&state)
254  {
255  JLM_ASSERT(is<MemoryStateType>(state.Type()));
256  }
257 
258  public:
259  [[nodiscard]] PointsToGraph::NodeIndex
260  MemoryNode() const noexcept
261  {
262  return MemoryNode_;
263  }
264 
265  [[nodiscard]] rvsdg::Output &
266  State() const noexcept
267  {
268  return *State_;
269  }
270 
271  void
272  ReplaceState(rvsdg::Output & state) noexcept
273  {
274  JLM_ASSERT(State_->region() == state.region());
275  JLM_ASSERT(is<MemoryStateType>(state.Type()));
276 
277  State_ = &state;
278  }
279 
280  static void
282  const std::vector<MemoryNodeStatePair *> & memoryNodeStatePairs,
283  const std::vector<rvsdg::Output *> & states)
284  {
285  JLM_ASSERT(memoryNodeStatePairs.size() == states.size());
286  for (size_t n = 0; n < memoryNodeStatePairs.size(); n++)
287  memoryNodeStatePairs[n]->ReplaceState(*states[n]);
288  }
289 
290  static void
292  const std::vector<MemoryNodeStatePair *> & memoryNodeStatePairs,
293  const rvsdg::Node::OutputIteratorRange & states)
294  {
295  auto it = states.begin();
296  for (auto memoryNodeStatePair : memoryNodeStatePairs)
297  {
298  memoryNodeStatePair->ReplaceState(*it);
299  it++;
300  }
301  JLM_ASSERT(it.GetOutput() == nullptr);
302  }
303 
304  static std::vector<rvsdg::Output *>
305  States(const std::vector<MemoryNodeStatePair *> & memoryNodeStatePairs)
306  {
307  std::vector<rvsdg::Output *> states;
308  for (auto & memoryNodeStatePair : memoryNodeStatePairs)
309  states.push_back(memoryNodeStatePair->State_);
310 
311  return states;
312  }
313 
314  private:
317  };
318 
319  StateMap() = default;
320 
321  StateMap(const StateMap &) = delete;
322 
323  StateMap(StateMap &&) = delete;
324 
325  StateMap &
326  operator=(const StateMap &) = delete;
327 
328  StateMap &
329  operator=(StateMap &&) = delete;
330 
333  {
334  if (const auto it = states_.find(memoryNode); it != states_.end())
335  return &it->second;
336 
337  return nullptr;
338  }
339 
340  const MemoryNodeStatePair *
341  TryGetState(PointsToGraph::NodeIndex memoryNode) const noexcept
342  {
343  return const_cast<StateMap *>(this)->TryGetState(memoryNode);
344  }
345 
346  bool
347  HasState(PointsToGraph::NodeIndex memoryNode) const noexcept
348  {
349  return TryGetState(memoryNode) != nullptr;
350  }
351 
352  MemoryNodeStatePair *
354  {
355  if (const auto statePair = TryGetState(memoryNode))
356  return statePair;
357  throw std::logic_error("Memory node does not have a state.");
358  }
359 
360  std::vector<MemoryNodeStatePair *>
362  {
363  std::vector<MemoryNodeStatePair *> memoryNodeStatePairs;
364  for (auto & memoryNode : memoryNodes.Items())
365  {
366  memoryNodeStatePairs.push_back(GetState(memoryNode));
367  }
368 
369  return memoryNodeStatePairs;
370  }
371 
379  std::vector<MemoryNodeStatePair *>
381  {
382  std::vector<MemoryNodeStatePair *> memoryNodeStatePairs;
383  for (auto & memoryNode : memoryNodes.Items())
384  {
385  if (const auto statePair = TryGetState(memoryNode))
386  memoryNodeStatePairs.push_back(statePair);
387  }
388 
389  return memoryNodeStatePairs;
390  }
391 
399  MemoryNodeStatePair *
401  {
402  auto [it, added] = states_.insert({ memoryNode, { memoryNode, state } });
403  if (!added)
404  throw std::logic_error("Memory node already has a state.");
405  return &it->second;
406  }
407 
408  static std::unique_ptr<StateMap>
410  {
411  return std::make_unique<StateMap>();
412  }
413 
414 private:
415  // std::unordered_map guarantees pointers to keys and values remain valid even when
416  // new pairs are added to the container.
417  std::unordered_map<PointsToGraph::NodeIndex, MemoryNodeStatePair> states_;
418 };
419 
423 {
424 public:
426  {
427  // Ensure that a PopRegion() was invoked for each invocation of a PushRegion().
428  JLM_ASSERT(StateMaps_.empty());
429  }
430 
431  explicit RegionalizedStateMap(const ModRefSummary & modRefSummary)
432  : ModRefSummary_(modRefSummary)
433  {}
434 
436 
438 
440  operator=(const RegionalizedStateMap &) = delete;
441 
444 
447  {
448  return GetStateMap(*state.region()).InsertState(memoryNode, state);
449  }
450 
452  TryGetState(const rvsdg::Region & region, PointsToGraph::NodeIndex memoryNode) const
453  {
454  return GetStateMap(region).TryGetState(memoryNode);
455  }
456 
457  bool
458  HasState(const rvsdg::Region & region, PointsToGraph::NodeIndex memoryNode) const
459  {
460  return GetStateMap(region).HasState(memoryNode);
461  }
462 
464  GetState(const rvsdg::Region & region, PointsToGraph::NodeIndex memoryNode)
465  {
466  return GetStateMap(region).GetState(memoryNode);
467  }
468 
469  std::vector<StateMap::MemoryNodeStatePair *>
471  const rvsdg::Region & region,
472  const util::HashSet<PointsToGraph::NodeIndex> & memoryNodes)
473  {
474  return GetStateMap(region).GetStates(memoryNodes);
475  }
476 
487  std::vector<StateMap::MemoryNodeStatePair *>
489  const rvsdg::Region & region,
490  const util::HashSet<PointsToGraph::NodeIndex> & memoryNodes) const
491  {
492  return GetStateMap(region).GetExistingStates(memoryNodes);
493  }
494 
495  std::vector<StateMap::MemoryNodeStatePair *>
497  {
498  return GetExistingStates(*node.region(), GetSimpleNodeModRef(node));
499  }
500 
503  {
504  return ModRefSummary_.GetSimpleNodeModRef(node);
505  }
506 
507  void
508  PushRegion(const rvsdg::Region & region)
509  {
510  JLM_ASSERT(StateMaps_.find(&region) == StateMaps_.end());
511  StateMaps_[&region] = StateMap::Create();
512  }
513 
514  void
515  PopRegion(const rvsdg::Region & region)
516  {
517  JLM_ASSERT(StateMaps_.find(&region) != StateMaps_.end());
518  StateMaps_.erase(&region);
519  }
520 
521 private:
522  StateMap &
523  GetStateMap(const rvsdg::Region & region) const noexcept
524  {
525  JLM_ASSERT(StateMaps_.find(&region) != StateMaps_.end());
526  return *StateMaps_.at(&region);
527  }
528 
530 
531  std::unordered_map<const rvsdg::Region *, std::unique_ptr<StateMap>> StateMaps_;
532 };
533 
537 {
538 public:
539  explicit Context(const ModRefSummary & modRefSummary)
540  : RegionalizedStateMap_(modRefSummary),
541  ModRefSummary_(modRefSummary)
542  {}
543 
544  Context(const Context &) = delete;
545 
546  Context(Context &&) = delete;
547 
548  Context &
549  operator=(const Context &) = delete;
550 
551  Context &
552  operator=(Context &&) = delete;
553 
556  {
557  return RegionalizedStateMap_;
558  }
559 
560  const ModRefSummary &
561  GetModRefSummary() const noexcept
562  {
563  return ModRefSummary_;
564  }
565 
568  {
570  }
571 
574  {
575  return LoadCounter_;
576  }
577 
580  {
581  return StoreCounter_;
582  }
583 
586  {
587  return CallEntryMergeCounter_;
588  }
589 
590  static std::unique_ptr<MemoryStateEncoder::Context>
591  Create(const ModRefSummary & modRefSummary)
592  {
593  return std::make_unique<Context>(modRefSummary);
594  }
595 
596 private:
599 
600  // Counters used for producing statistics about memory states
605 };
606 
607 static std::vector<MemoryNodeId>
609 {
610  std::vector<MemoryNodeId> memoryNodeIds;
611  for (const auto memoryNode : memoryNodes.Items())
612  {
613  memoryNodeIds.push_back(memoryNode);
614  }
615 
616  return memoryNodeIds;
617 }
618 
619 MemoryStateEncoder::~MemoryStateEncoder() noexcept = default;
620 
621 MemoryStateEncoder::MemoryStateEncoder() = default;
622 
623 void
625  rvsdg::RvsdgModule & rvsdgModule,
626  const ModRefSummary & modRefSummary,
627  util::StatisticsCollector & statisticsCollector)
628 {
629  Context_ = Context::Create(modRefSummary);
630  auto statistics = EncodingStatistics::Create(rvsdgModule.SourceFilePath().value());
631 
632  statistics->Start(rvsdgModule.Rvsdg());
633  EncodeRegion(rvsdgModule.Rvsdg().GetRootRegion());
634  statistics->Stop();
635 
636  statistics->AddIntraProceduralRegionMemoryStateCounts(
637  Context_->GetInterProceduralRegionCounter());
638  statistics->AddLoadMemoryStateCounts(Context_->GetLoadCounter());
639  statistics->AddStoreMemoryStateCounts(Context_->GetStoreCounter());
640  statistics->AddCallEntryMergeStateCounts(Context_->GetCallEntryMergeCounter());
641 
642  statisticsCollector.CollectDemandedStatistics(std::move(statistics));
643 
644  // Discard internal state to free up memory after we are done with the encoding
645  Context_.reset();
646 
647  // Remove all nodes that became dead throughout the encoding.
648  DeadNodeElimination deadNodeElimination;
649  deadNodeElimination.Run(rvsdgModule, statisticsCollector);
650 }
651 
652 void
654 {
655  using namespace jlm::rvsdg;
656 
657  TopDownTraverser traverser(&region);
658  for (const auto node : traverser)
659  {
661  *node,
662  [&](SimpleNode & simpleNode)
663  {
664  EncodeSimpleNode(simpleNode);
665  },
666  [&](StructuralNode & structuralNode)
667  {
668  EncodeStructuralNode(structuralNode);
669  });
670  }
671 }
672 
673 void
675 {
676  if (auto lambdaNode = dynamic_cast<const rvsdg::LambdaNode *>(&structuralNode))
677  {
678  EncodeLambda(*lambdaNode);
679  }
680  else if (auto deltaNode = dynamic_cast<const rvsdg::DeltaNode *>(&structuralNode))
681  {
682  EncodeDelta(*deltaNode);
683  }
684  else if (auto phiNode = dynamic_cast<const rvsdg::PhiNode *>(&structuralNode))
685  {
686  EncodePhi(*phiNode);
687  }
688  else if (auto gammaNode = dynamic_cast<rvsdg::GammaNode *>(&structuralNode))
689  {
690  EncodeGamma(*gammaNode);
691  }
692  else if (auto thetaNode = dynamic_cast<rvsdg::ThetaNode *>(&structuralNode))
693  {
694  EncodeTheta(*thetaNode);
695  }
696  else
697  {
698  JLM_UNREACHABLE("Unhandled node type.");
699  }
700 }
701 
702 void
704 {
706  simpleNode.GetOperation(),
707  [&](const AllocaOperation &)
708  {
709  EncodeAlloca(simpleNode);
710  },
711  [&](const MallocOperation &)
712  {
713  EncodeMalloc(simpleNode);
714  },
715  [&](const LoadOperation &)
716  {
717  EncodeLoad(simpleNode);
718  },
719  [&](const StoreOperation &)
720  {
721  EncodeStore(simpleNode);
722  },
723  [&](const CallOperation &)
724  {
725  EncodeCall(simpleNode);
726  },
727  [&](const FreeOperation &)
728  {
729  EncodeFree(simpleNode);
730  },
731  [&](const MemCpyOperation &)
732  {
733  EncodeMemcpy(simpleNode);
734  },
735  [&](const MemoryStateOperation &)
736  {
737  // Nothing needs to be done
738  },
739  [&]()
740  {
741  // Ensure we took care of all memory state consuming/producing nodes
742  JLM_ASSERT(!hasMemoryState(simpleNode));
743  });
744 }
745 
746 void
748 {
749  JLM_ASSERT(is<AllocaOperation>(allocaNode.GetOperation()));
750 
751  auto & stateMap = Context_->GetRegionalizedStateMap();
752  auto allocaMemoryNodes = stateMap.GetSimpleNodeModRef(allocaNode);
753  JLM_ASSERT(allocaMemoryNodes.Size() == 1);
754  auto allocaMemoryNode = *allocaMemoryNodes.Items().begin();
755  auto & allocaNodeStateOutput = *allocaNode.output(1);
756 
757  // If a state representing the alloca already exists in the region,
758  // merge it with the state created by the alloca using a MemoryStateJoin node.
759  if (const auto statePair = stateMap.TryGetState(*allocaNode.region(), allocaMemoryNode))
760  {
761  auto & joinNode =
762  MemoryStateJoinOperation::CreateNode({ &allocaNodeStateOutput, &statePair->State() });
763  auto & joinOutput = *joinNode.output(0);
764  statePair->ReplaceState(joinOutput);
765  }
766  else
767  {
768  stateMap.InsertState(allocaMemoryNode, allocaNodeStateOutput);
769  }
770 }
771 
772 void
774 {
775  JLM_ASSERT(is<MallocOperation>(mallocNode.GetOperation()));
776  auto & stateMap = Context_->GetRegionalizedStateMap();
777  auto mallocMemoryNodes = stateMap.GetSimpleNodeModRef(mallocNode);
778  JLM_ASSERT(mallocMemoryNodes.Size() == 1);
779  auto mallocMemoryNode = *mallocMemoryNodes.Items().begin();
780 
781  auto & mallocNodeStateOutput = MallocOperation::memoryStateOutput(mallocNode);
782 
783  // We use a static heap model. This means that multiple invocations of an malloc
784  // at runtime can refer to the same abstract memory location. We therefore need to
785  // merge the previous and the current state to ensure that the previous state
786  // is not just simply replaced and therefore "lost".
787  if (const auto statePair = stateMap.TryGetState(*mallocNode.region(), mallocMemoryNode))
788  {
789  auto & joinNode =
790  MemoryStateJoinOperation::CreateNode({ &mallocNodeStateOutput, &statePair->State() });
791  auto & joinOutput = *joinNode.output(0);
792  statePair->ReplaceState(joinOutput);
793  }
794  else
795  {
796  stateMap.InsertState(mallocMemoryNode, mallocNodeStateOutput);
797  }
798 }
799 
800 void
802 {
803  JLM_ASSERT(is<LoadOperation>(node.GetOperation()));
804  auto & stateMap = Context_->GetRegionalizedStateMap();
805 
806  const auto & memoryNodes = stateMap.GetSimpleNodeModRef(node);
807  Context_->GetLoadCounter().CountEntity(
808  Context_->GetModRefSummary().GetPointsToGraph(),
809  memoryNodes);
810 
811  const auto memoryNodeStatePairs = stateMap.GetExistingStates(*node.region(), memoryNodes);
812  const auto memoryStates = StateMap::MemoryNodeStatePair::States(memoryNodeStatePairs);
813 
814  const auto & newLoadNode = ReplaceLoadNode(node, memoryStates);
815 
817  memoryNodeStatePairs,
818  LoadOperation::MemoryStateOutputs(newLoadNode));
819 }
820 
821 void
823 {
824  auto & stateMap = Context_->GetRegionalizedStateMap();
825 
826  const auto & memoryNodes = stateMap.GetSimpleNodeModRef(node);
827  Context_->GetStoreCounter().CountEntity(
828  Context_->GetModRefSummary().GetPointsToGraph(),
829  memoryNodes);
830 
831  const auto memoryNodeStatePairs = stateMap.GetExistingStates(*node.region(), memoryNodes);
832  const auto memoryStates = StateMap::MemoryNodeStatePair::States(memoryNodeStatePairs);
833 
834  const auto & newStoreNode = ReplaceStoreNode(node, memoryStates);
835 
837  memoryNodeStatePairs,
838  StoreOperation::MemoryStateOutputs(newStoreNode));
839 }
840 
841 void
843 {
844  JLM_ASSERT(is<FreeOperation>(freeNode.GetOperation()));
845  auto & stateMap = Context_->GetRegionalizedStateMap();
846 
847  auto address = freeNode.input(0)->origin();
848  auto ioState = freeNode.input(freeNode.ninputs() - 1)->origin();
849  auto memoryNodeStatePairs = stateMap.GetExistingStates(freeNode);
850  auto inStates = StateMap::MemoryNodeStatePair::States(memoryNodeStatePairs);
851 
852  auto outputs = FreeOperation::Create(address, inStates, ioState);
853 
854  // Redirect IO state edge
855  freeNode.output(freeNode.noutputs() - 1)->divert_users(outputs.back());
856 
858  memoryNodeStatePairs,
859  { outputs.begin(), std::prev(outputs.end()) });
860 }
861 
862 void
864 {
865  const auto region = callNode.region();
866  auto & regionalizedStateMap = Context_->GetRegionalizedStateMap();
867 
868  const auto & memoryNodes = regionalizedStateMap.GetSimpleNodeModRef(callNode);
869  Context_->GetCallEntryMergeCounter().CountEntity(
870  Context_->GetModRefSummary().GetPointsToGraph(),
871  memoryNodes);
872 
873  const auto statePairs = regionalizedStateMap.GetExistingStates(*region, memoryNodes);
874 
875  std::vector<rvsdg::Output *> inputStates;
876  std::vector<MemoryNodeId> memoryNodeIds;
877  for (auto statePair : statePairs)
878  {
879  inputStates.emplace_back(&statePair->State());
880  memoryNodeIds.push_back(statePair->MemoryNode());
881  }
882 
883  auto & entryMergeNode =
884  CallEntryMemoryStateMergeOperation::CreateNode(*region, inputStates, memoryNodeIds);
885  CallOperation::GetMemoryStateInput(callNode).divert_to(entryMergeNode.output(0));
886 
887  auto & exitSplitNode = CallExitMemoryStateSplitOperation::CreateNode(
889  memoryNodeIds);
890 
892 }
893 
894 void
896 {
897  JLM_ASSERT(is<MemCpyOperation>(memcpyNode.GetOperation()));
898  auto & stateMap = Context_->GetRegionalizedStateMap();
899 
900  auto memoryNodeStatePairs = stateMap.GetExistingStates(memcpyNode);
901  auto memoryStateOperands = StateMap::MemoryNodeStatePair::States(memoryNodeStatePairs);
902 
903  auto memoryStateResults = ReplaceMemcpyNode(memcpyNode, memoryStateOperands);
904 
905  StateMap::MemoryNodeStatePair::ReplaceStates(memoryNodeStatePairs, memoryStateResults);
906 }
907 
908 void
910 {
911  EncodeLambdaEntry(lambdaNode);
912  EncodeRegion(*lambdaNode.subregion());
913  EncodeLambdaExit(lambdaNode);
914 }
915 
916 void
918 {
919  auto & memoryStateArgument = GetMemoryStateRegionArgument(lambdaNode);
920 
921  const auto & memoryNodes = Context_->GetModRefSummary().GetLambdaEntryModRef(lambdaNode);
922  Context_->GetInterProceduralRegionCounter().CountEntity(
923  Context_->GetModRefSummary().GetPointsToGraph(),
924  memoryNodes);
925 
926  const auto memoryNodeIds = GetMemoryNodeIds(memoryNodes);
927  auto & stateMap = Context_->GetRegionalizedStateMap();
928 
929  stateMap.PushRegion(*lambdaNode.subregion());
930  auto & lambdaEntrySplitNode =
931  LambdaEntryMemoryStateSplitOperation::CreateNode(memoryStateArgument, memoryNodeIds);
932  const auto states = rvsdg::outputs(&lambdaEntrySplitNode);
933 
934  size_t n = 0;
935  for (auto & memoryNode : memoryNodes.Items())
936  stateMap.InsertState(memoryNode, *states[n++]);
937 
938  if (!states.empty())
939  {
940  // This additional MemoryStateMergeOperation node makes all other nodes in the function that
941  // consume the memory state dependent on this node and therefore transitively on the
942  // LambdaEntryMemoryStateSplitOperation. This ensures that the
943  // LambdaEntryMemoryStateSplitOperation is always visited before all other memory state
944  // consuming nodes:
945  //
946  // ... := LAMBDA[f]
947  // [..., a1, ...]
948  // o1, ..., ox := LambdaEntryMemoryStateSplit a1
949  // oy = MemoryStateMerge o1, ..., ox
950  // ....
951  //
952  // No other memory state consuming node aside from the LambdaEntryMemoryStateSplitOperation
953  // should now consume a1.
954  auto state = MemoryStateMergeOperation::Create(states);
955  memoryStateArgument.divertUsersWhere(
956  *state,
957  [&lambdaEntrySplitNode](const rvsdg::Input & user)
958  {
959  return rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(user) != &lambdaEntrySplitNode;
960  });
961  }
962 }
963 
964 void
966 {
967  const auto & memoryNodes = Context_->GetModRefSummary().GetLambdaExitModRef(lambdaNode);
968  auto & stateMap = Context_->GetRegionalizedStateMap();
969  auto & memoryStateResult = GetMemoryStateRegionResult(lambdaNode);
970 
971  std::vector<rvsdg::Output *> states;
972  std::vector<MemoryNodeId> memoryNodeIds;
973  auto & subregion = *lambdaNode.subregion();
974  const auto memoryNodeStatePairs = stateMap.GetStates(subregion, memoryNodes);
975  for (const auto memoryNodeStatePair : memoryNodeStatePairs)
976  {
977  states.push_back(&memoryNodeStatePair->State());
978  memoryNodeIds.push_back(memoryNodeStatePair->MemoryNode());
979  }
980 
981  const auto mergedState =
982  LambdaExitMemoryStateMergeOperation::CreateNode(subregion, states, memoryNodeIds).output(0);
983  memoryStateResult.divert_to(mergedState);
984 
985  stateMap.PopRegion(*lambdaNode.subregion());
986 }
987 
988 void
990 {
991  EncodeRegion(*phiNode.subregion());
992 }
993 
994 void
996 {
997  // Nothing needs to be done
998 }
999 
1000 void
1002 {
1003  for (auto & subregion : gammaNode.Subregions())
1004  Context_->GetRegionalizedStateMap().PushRegion(subregion);
1005 
1006  EncodeGammaEntry(gammaNode);
1007 
1008  for (auto & subregion : gammaNode.Subregions())
1009  EncodeRegion(subregion);
1010 
1011  EncodeGammaExit(gammaNode);
1012 
1013  for (auto & subregion : gammaNode.Subregions())
1014  Context_->GetRegionalizedStateMap().PopRegion(subregion);
1015 }
1016 
1017 void
1019 {
1020  auto region = gammaNode.region();
1021  auto & stateMap = Context_->GetRegionalizedStateMap();
1022  auto memoryNodes = Context_->GetModRefSummary().GetGammaEntryModRef(gammaNode);
1023 
1024  // Count the memory state arguments once per subregion
1025  for ([[maybe_unused]] auto & subregion : gammaNode.Subregions())
1026  Context_->GetInterProceduralRegionCounter().CountEntity(
1027  Context_->GetModRefSummary().GetPointsToGraph(),
1028  memoryNodes);
1029 
1030  auto memoryNodeStatePairs = stateMap.GetExistingStates(*region, memoryNodes);
1031  for (auto & memoryNodeStatePair : memoryNodeStatePairs)
1032  {
1033  auto gammaInput = gammaNode.AddEntryVar(&memoryNodeStatePair->State());
1034  for (auto & argument : gammaInput.branchArgument)
1035  stateMap.InsertState(memoryNodeStatePair->MemoryNode(), *argument);
1036  }
1037 }
1038 
1039 void
1041 {
1042  auto & stateMap = Context_->GetRegionalizedStateMap();
1043  auto memoryNodes = Context_->GetModRefSummary().GetGammaExitModRef(gammaNode);
1044  auto memoryNodeStatePairs = stateMap.GetExistingStates(*gammaNode.region(), memoryNodes);
1045 
1046  for (auto & memoryNodeStatePair : memoryNodeStatePairs)
1047  {
1048  std::vector<rvsdg::Output *> states;
1049 
1050  for (auto & subregion : gammaNode.Subregions())
1051  {
1052  auto & state = stateMap.GetState(subregion, memoryNodeStatePair->MemoryNode())->State();
1053  states.push_back(&state);
1054  }
1055 
1056  auto state = gammaNode.AddExitVar(states).output;
1057  memoryNodeStatePair->ReplaceState(*state);
1058  }
1059 }
1060 
1061 void
1063 {
1064  Context_->GetRegionalizedStateMap().PushRegion(*thetaNode.subregion());
1065 
1066  auto thetaStateOutputs = EncodeThetaEntry(thetaNode);
1067  EncodeRegion(*thetaNode.subregion());
1068  EncodeThetaExit(thetaNode, thetaStateOutputs);
1069 
1070  Context_->GetRegionalizedStateMap().PopRegion(*thetaNode.subregion());
1071 }
1072 
1073 std::vector<rvsdg::Output *>
1075 {
1076  auto region = thetaNode.region();
1077  auto & stateMap = Context_->GetRegionalizedStateMap();
1078  const auto & memoryNodes = Context_->GetModRefSummary().GetThetaModRef(thetaNode);
1079  Context_->GetInterProceduralRegionCounter().CountEntity(
1080  Context_->GetModRefSummary().GetPointsToGraph(),
1081  memoryNodes);
1082 
1083  std::vector<rvsdg::Output *> thetaStateOutputs;
1084  auto memoryNodeStatePairs = stateMap.GetExistingStates(*region, memoryNodes);
1085  for (auto & memoryNodeStatePair : memoryNodeStatePairs)
1086  {
1087  auto loopvar = thetaNode.AddLoopVar(&memoryNodeStatePair->State());
1088  stateMap.InsertState(memoryNodeStatePair->MemoryNode(), *loopvar.pre);
1089  thetaStateOutputs.push_back(loopvar.output);
1090  }
1091 
1092  return thetaStateOutputs;
1093 }
1094 
1095 void
1097  rvsdg::ThetaNode & thetaNode,
1098  const std::vector<rvsdg::Output *> & thetaStateOutputs)
1099 {
1100  auto subregion = thetaNode.subregion();
1101  auto & stateMap = Context_->GetRegionalizedStateMap();
1102  const auto & memoryNodes = Context_->GetModRefSummary().GetThetaModRef(thetaNode);
1103  auto memoryNodeStatePairs = stateMap.GetExistingStates(*thetaNode.region(), memoryNodes);
1104 
1105  JLM_ASSERT(memoryNodeStatePairs.size() == thetaStateOutputs.size());
1106  for (size_t n = 0; n < thetaStateOutputs.size(); n++)
1107  {
1108  auto thetaStateOutput = thetaStateOutputs[n];
1109  auto & memoryNodeStatePair = memoryNodeStatePairs[n];
1110  auto memoryNode = memoryNodeStatePair->MemoryNode();
1111  auto loopvar = thetaNode.MapOutputLoopVar(*thetaStateOutput);
1112  JLM_ASSERT(loopvar.input->origin() == &memoryNodeStatePair->State());
1113 
1114  auto & subregionState = stateMap.GetState(*subregion, memoryNode)->State();
1115  loopvar.post->divert_to(&subregionState);
1116  memoryNodeStatePair->ReplaceState(*thetaStateOutput);
1117  }
1118 }
1119 
1122  const rvsdg::SimpleNode & node,
1123  const std::vector<rvsdg::Output *> & memoryStates)
1124 {
1125  JLM_ASSERT(is<LoadOperation>(node.GetOperation()));
1126 
1127  if (const auto loadVolatileOperation =
1128  dynamic_cast<const LoadVolatileOperation *>(&node.GetOperation()))
1129  {
1130  auto & newLoadNode = LoadVolatileOperation::CreateNode(
1131  *LoadOperation::AddressInput(node).origin(),
1132  *LoadVolatileOperation::IOStateInput(node).origin(),
1133  memoryStates,
1134  loadVolatileOperation->GetLoadedType(),
1135  loadVolatileOperation->GetAlignment());
1136  auto & oldLoadedValueOutput = LoadOperation::LoadedValueOutput(node);
1137  auto & newLoadedValueOutput = LoadOperation::LoadedValueOutput(newLoadNode);
1138  auto & oldIOStateOutput = LoadVolatileOperation::IOStateOutput(node);
1139  auto & newIOStateOutput = LoadVolatileOperation::IOStateOutput(newLoadNode);
1140  oldLoadedValueOutput.divert_users(&newLoadedValueOutput);
1141  oldIOStateOutput.divert_users(&newIOStateOutput);
1142  return newLoadNode;
1143  }
1144 
1145  if (const auto loadNonVolatileOperation =
1146  dynamic_cast<const LoadNonVolatileOperation *>(&node.GetOperation()))
1147  {
1148  auto & newLoadNode = LoadNonVolatileOperation::CreateNode(
1149  *LoadOperation::AddressInput(node).origin(),
1150  memoryStates,
1151  loadNonVolatileOperation->GetLoadedType(),
1152  loadNonVolatileOperation->GetAlignment());
1153  auto & oldLoadedValueOutput = LoadOperation::LoadedValueOutput(node);
1154  auto & newLoadedValueOutput = LoadNonVolatileOperation::LoadedValueOutput(newLoadNode);
1155  oldLoadedValueOutput.divert_users(&newLoadedValueOutput);
1156  return newLoadNode;
1157  }
1158 
1159  JLM_UNREACHABLE("Unhandled load node type.");
1160 }
1161 
1164  const rvsdg::SimpleNode & node,
1165  const std::vector<rvsdg::Output *> & memoryStates)
1166 {
1167  if (const auto oldStoreVolatileOperation =
1168  dynamic_cast<const StoreVolatileOperation *>(&node.GetOperation()))
1169  {
1170  auto & newStoreNode = StoreVolatileOperation::CreateNode(
1171  *StoreOperation::AddressInput(node).origin(),
1172  *StoreOperation::StoredValueInput(node).origin(),
1173  *StoreVolatileOperation::IOStateInput(node).origin(),
1174  memoryStates,
1175  oldStoreVolatileOperation->GetAlignment());
1176  auto & oldIOStateOutput = StoreVolatileOperation::IOStateOutput(node);
1177  auto & newIOStateOutput = StoreVolatileOperation::IOStateOutput(newStoreNode);
1178  oldIOStateOutput.divert_users(&newIOStateOutput);
1179  return newStoreNode;
1180  }
1181 
1182  if (const auto oldStoreNonVolatileOperation =
1183  dynamic_cast<const StoreNonVolatileOperation *>(&node.GetOperation()))
1184  {
1186  *StoreOperation::AddressInput(node).origin(),
1187  *StoreOperation::StoredValueInput(node).origin(),
1188  memoryStates,
1189  oldStoreNonVolatileOperation->GetAlignment());
1190  }
1191 
1192  JLM_UNREACHABLE("Unhandled store node type.");
1193 }
1194 
1195 std::vector<rvsdg::Output *>
1197  const rvsdg::SimpleNode & memcpyNode,
1198  const std::vector<rvsdg::Output *> & memoryStates)
1199 {
1200  JLM_ASSERT(is<MemCpyOperation>(memcpyNode.GetOperation()));
1201 
1202  auto destination = memcpyNode.input(0)->origin();
1203  auto source = memcpyNode.input(1)->origin();
1204  auto length = memcpyNode.input(2)->origin();
1205 
1206  if (is<MemCpyVolatileOperation>(memcpyNode.GetOperation()))
1207  {
1208  auto & ioState = *memcpyNode.input(3)->origin();
1209  auto & newMemcpyNode =
1210  MemCpyVolatileOperation::CreateNode(*destination, *source, *length, ioState, memoryStates);
1211  auto results = rvsdg::outputs(&newMemcpyNode);
1212 
1213  // Redirect I/O state
1214  memcpyNode.output(0)->divert_users(results[0]);
1215 
1216  // Skip I/O state and only return memory states
1217  return { std::next(results.begin()), results.end() };
1218  }
1219  if (is<MemCpyNonVolatileOperation>(memcpyNode.GetOperation()))
1220  {
1221  return MemCpyNonVolatileOperation::create(destination, source, length, memoryStates);
1222  }
1223 
1224  throw std::logic_error("Unhandled memcpy operation type.");
1225 }
1226 
1227 }
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:249
static rvsdg::Input & GetMemoryStateInput(const rvsdg::Node &node) noexcept
Definition: call.hpp:338
static rvsdg::Output & GetMemoryStateOutput(const rvsdg::Node &node) noexcept
Definition: call.hpp:350
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:2554
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::Node & 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:451
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:101
static rvsdg::Input & IOStateInput(const rvsdg::Node &node) noexcept
Definition: Load.hpp:210
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< LoadVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
Definition: Load.cpp:390
static rvsdg::Output & IOStateOutput(const rvsdg::Node &node)
Definition: Load.hpp:219
static rvsdg::Output & memoryStateOutput(const rvsdg::Node &node)
Definition: operators.hpp:2472
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *destination, const Variable *source, const Variable *length, const std::vector< const Variable * > &memoryStates)
Definition: MemCpy.hpp:173
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &destination, rvsdg::Output &source, rvsdg::Output &length, rvsdg::Output &ioState, const std::vector< rvsdg::Output * > &memoryStates)
Definition: MemCpy.hpp:286
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:300
static rvsdg::Input & StoredValueInput(const rvsdg::Node &node) noexcept
Definition: Store.hpp:84
static rvsdg::Node::OutputIteratorRange MemoryStateOutputs(const rvsdg::SimpleNode &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:407
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< StoreVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition: Store.hpp:430
static rvsdg::Input & IOStateInput(const rvsdg::Node &node) noexcept
Definition: Store.hpp:398
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)
void EncodeMemcpy(const rvsdg::SimpleNode &memcpyNode)
void EncodeGamma(rvsdg::GammaNode &gammaNode)
void EncodeFree(const rvsdg::SimpleNode &freeNode)
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(std::vector< rvsdg::Output * > values)
Routes per-branch result of gamma to output.
Definition: gamma.cpp:342
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
NodeOutput * output(size_t index) const noexcept
Definition: node.hpp:650
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
Statistics Interface.
Definition: Statistics.hpp:31
util::Timer & GetTimer(const std::string &name)
Definition: Statistics.cpp:134
Statistics(const Statistics::Id &statisticsId, util::FilePath sourceFile)
Definition: Statistics.hpp:73
util::Timer & AddTimer(std::string name)
Definition: Statistics.cpp:155
void AddMeasurement(std::string name, T value)
Definition: Statistics.hpp:174
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:629
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:211
static const char * Timer
Definition: Statistics.hpp:240