Joos1W Compiler Framework
All Classes Functions Typedefs Pages
PassManager.cc
1 #include <third-party/CLI11.h>
2 #include <utils/Error.h>
3 #include <utils/PassManager.h>
4 
5 namespace utils {
6 
7 /* ===--------------------------------------------------------------------=== */
8 // PassOptions
9 /* ===--------------------------------------------------------------------=== */
10 
11 bool PassOptions::IsPassDisabled(Pass* p) {
12  auto it = pass_descs_.find(std::string{p->Name()});
13  if(it == pass_descs_.end()) return false;
14  return !it->second.enabled;
15 }
16 
17 void PassOptions::setPassEnabled(Pass* p, bool enabled) {
18  pass_descs_[std::string{p->Name()}].enabled = enabled;
19 }
20 
21 /* ===--------------------------------------------------------------------=== */
22 // Pass
23 /* ===--------------------------------------------------------------------=== */
24 
25 void Pass::ComputeDependency(Pass& pass) {
26  // This function serves a many purposes depending on the state
27  // 1. PropagateEnabled: Recursively propagate the enabled state
28  // 2. AcquireResources: We acquire any heap resources
29  // 3. RegisterDependencies: Register the dep with PM to build the depgraph
30  // 4. Cleanup: We only free the heap resources
31 
32  if(state == PropagateEnabled) {
33  // If we're disabled, then we don't need to do anything
34  if(PM().PO().IsPassDisabled(this)) return;
35  // Otherwise, we propagate the enabled state
36  PM().PO().setPassEnabled(&pass, true);
37  pass.state = PropagateEnabled;
38  pass.computeDependencies();
39  return;
40  }
41 
42  for(auto& heap : PM().heaps_) {
43  if(heap.owner != &pass) continue;
44  if(state == AcquireResources) {
45  heap.refCount++;
46  } else if(state == Cleanup) {
47  PM().freeHeap(heap);
48  }
49  }
50 
51  if(state == RegisterDependencies) {
52  PM().addDependency(*this, pass);
53  }
54 }
55 
56 CustomBufferResource* Pass::NewHeap() { return PM().newHeap(*this); }
57 
58 void Pass::RegisterCLI() {
59  auto& PO = PM().PO();
60  PO.pass_descs_[std::string{Name()}] =
61  PassOptions::PassDesc{false, std::string{Desc()}};
62 }
63 
64 Pass& Pass::GetPass(std::string_view name) { return PM().getPass(name); }
65 
66 /* ===--------------------------------------------------------------------=== */
67 // PassManager
68 /* ===--------------------------------------------------------------------=== */
69 
70 CustomBufferResource* PassManager::newHeap(Pass& pass) {
71  // Check the pass is running
72  if(pass.state != Pass::Running && pass.state != Pass::AcquireResources) {
73  throw utils::FatalError("Pass requesting a heap is not running");
74  }
75  // First, find a free heap
76  for(auto& heap : heaps_) {
77  if(heap.owner != nullptr) continue;
78  // We found a free heap, so we can use it
79  heap.refCount = pass.ShouldPreserve() ? 2 : 1;
80  heap.owner = &pass;
81  return heap.heap.get();
82  }
83  // If we can't find a free heap, then create a new one
84  heaps_.emplace_back(&pass);
85  return heaps_.back().heap.get();
86 }
87 
88 void PassManager::freeHeap(Heap& h) {
89  // If fully is true, then we destroy the heap
90  // Otherwise, just decrement the ref count
91  if(h.refCount > 0) {
92  h.refCount--;
93  }
94  // If the ref count is 0, then we can destroy the heap
95  if(h.refCount == 0) {
96  if(Diag().Verbose(2)) {
97  Diag().ReportDebug() << "[=>] Freeing heap for " << h.owner->Desc();
98  }
99  if(reuseHeaps_) {
100  h.owner = nullptr;
101  h.heap->reset();
102  } else {
103  h.heap->destroy();
104  }
105  }
106  return;
107 }
108 
109 void PassManager::Reset() {
110  for(auto& heap : heaps_) {
111  heap.owner = nullptr;
112  heap.heap->reset();
113  }
114  depgraph_.clear();
115  lastRun_ = nullptr;
116  passDeps_.clear();
117  for(auto& pass : passes_) {
118  PO().setPassEnabled(pass.get(), false);
119  pass->state = Pass::Uninitialized;
120  }
121 }
122 
123 bool PassManager::Run() {
124  std::vector<Pass*> S;
125  std::vector<Pass*> L;
126  // 1a Propagate the enabled state
127  for(auto& pass : passes_) {
128  pass->state = Pass::PropagateEnabled;
129  pass->computeDependencies();
130  }
131  // 1b Acquire resources for the passes
132  for(auto& pass : passes_) {
133  // If the pass is disabled, then we skip it
134  if(PO().IsPassDisabled(pass.get())) continue;
135  pass->state = Pass::AcquireResources;
136  pass->Init();
137  }
138  // 1c Propagate the heap refcounts
139  for(auto& pass : passes_) {
140  if(PO().IsPassDisabled(pass.get())) continue;
141  pass->computeDependencies();
142  }
143  if(Diag().Verbose(2)) {
144  for(auto& heap : heaps_) {
145  Diag().ReportDebug(2) << "[=>] Heap Owner: \"" << heap.owner->Desc()
146  << "\" RefCount: " << heap.refCount;
147  }
148  }
149  // 2. Build the dependency graph of passes
150  size_t NumEnabledPasses = 0;
151  for(auto& pass : passes_) {
152  if(PO().IsPassDisabled(pass.get())) continue;
153  NumEnabledPasses++;
154  passDeps_[pass.get()] = 0;
155  pass->state = Pass::RegisterDependencies;
156  pass->computeDependencies();
157  // Mark the pass in the graph
158  if(passDeps_[pass.get()] == 0) S.push_back(pass.get());
159  }
160  // 3. Run topological sort on the dependency graph
161  while(!S.empty()) {
162  auto* n = *S.begin();
163  S.erase(S.begin());
164  L.push_back(n);
165  for(auto* m : depgraph_[n]) {
166  if(--passDeps_[m] == 0) S.push_back(m);
167  }
168  depgraph_[n].clear();
169  }
170  // 4. Check for cycles
171  if(L.size() != NumEnabledPasses)
172  throw utils::FatalError("Cyclic pass dependency detected");
173  // 5. Run the passes in topological order
174  for(auto& pass : L) {
175  assert(pass->state != Pass::Valid && "Pass already run");
176  pass->state = Pass::Running;
177  if(Diag().Verbose()) {
178  Diag().ReportDebug() << "[=>] Running " << pass->Desc() << " Pass";
179  }
180  pass->Run();
181  lastRun_ = pass;
182  if(Diag().hasErrors()) {
183  pass->state = Pass::Invalid;
184  return false;
185  } else if(Diag().hasWarnings()) {
186  pass->state = Pass::Invalid;
187  return false;
188  }
189  // If the pass is running, we can free the heaps by calling
190  // computeDependencies again
191  pass->state = Pass::Cleanup;
192  pass->computeDependencies();
193  // Update the pass state
194  pass->state = Pass::Valid;
195  }
196  return true;
197 }
198 
199 } // namespace utils