3 #include <utils/Error.h>
8 #include <unordered_map>
11 #include "diagnostics/Diagnostics.h"
12 #include "third-party/CLI11.h"
13 #include "utils/BumpAllocator.h"
14 #include "utils/Generator.h"
23 concept PassType = std::is_base_of_v<Pass, T>;
27 PassOptions(CLI::App& app) : app_{app} {}
32 ~PassOptions() =
default;
34 CLI::Option* FindOption(std::string_view name) {
35 std::string test_name =
"--" + get_single_name(name);
36 if(test_name.size() == 3) test_name.erase(0, 1);
37 return app_.get_option_no_throw(test_name);
40 CLI::Option* GetExistingOption(std::string name) {
41 auto opt = FindOption(name);
43 throw utils::FatalError(
"pass requested nonexistent option: " + name);
51 void EnablePass(std::string_view name,
bool enabled =
true) {
52 if(
auto it = pass_descs_.find(std::string{name});
53 it != pass_descs_.end()) {
54 it->second.enabled = enabled;
56 assert(
false &&
"Pass not found");
94 friend class PassManager;
104 std::unordered_map<std::string, PassDesc> pass_descs_;
114 Pass(
Pass const&) =
delete;
115 Pass(
Pass&&) =
delete;
116 Pass& operator=(
Pass const&) =
delete;
120 virtual ~Pass() =
default;
136 auto&
PM() {
return pm_; }
142 template <
typename T>
152 template <
typename T>
165 friend class PassManager;
170 explicit Pass(PassManager& pm)
noexcept : pm_(pm) {}
182 RegisterDependencies,
188 State state = State::Uninitialized;
189 bool preserve =
false;
196 class PassManager
final {
202 std::unique_ptr<CustomBufferResource> heap;
206 : heap{std::make_unique<CustomBufferResource>()},
212 PassManager(CLI::App& app) : options_{app}, reuseHeaps_{
true} {}
227 PassManager(PassManager
const&) =
delete;
228 PassManager(PassManager&&) =
delete;
229 PassManager& operator=(PassManager
const&) =
delete;
230 PassManager& operator=(PassManager&&) =
delete;
242 template <
typename T,
typename... Args>
244 T& AddPass(Args&&... args) {
245 passes_.emplace_back(
new T(*
this, std::forward<Args>(args)...));
246 T& result = *cast<T*>(passes_.back().get());
249 if(!result.Name().empty()) result.RegisterCLI();
254 diagnostics::DiagnosticEngine& Diag() {
return diag_; }
257 PassOptions& PO() {
return options_; }
260 template <
typename T>
264 for(
auto& pass : passes_) {
265 if(
auto* p = dyn_cast<T*>(pass.get())) {
266 if(result !=
nullptr)
267 throw utils::FatalError(
"Multiple passes of type: " +
268 std::string(
typeid(T).name()));
272 if(result ==
nullptr) {
273 throw utils::FatalError(
"Pass not found: " +
274 std::string(
typeid(T).name()));
280 template <
typename T>
282 void PreserveAnalysis() {
283 auto& pass = FindPass<T>();
288 template <
typename T>
290 T& getPass(Pass& pass) {
291 auto& result = FindPass<T>();
293 if(pass.state == Pass::Running && result.state != Pass::Valid) {
294 throw utils::FatalError(
"Pass not valid: " +
295 std::string(
typeid(T).name()));
300 template <
typename T>
302 Generator<T*> getPasses(Pass& pass) {
304 for(
auto& pass : passes_) {
305 if(
auto* p = dyn_cast<T*>(pass.get())) {
307 if(p->state == Pass::Running && p->state != Pass::Valid) {
308 throw utils::FatalError(
"Pass not valid: " +
309 std::string(
typeid(T).name()));
316 throw utils::FatalError(
"Pass of type not found: " +
317 std::string(
typeid(T).name()));
321 Pass& getPass(std::string_view name) {
322 for(
auto& pass : passes_)
323 if(pass->Name() == name)
return *pass;
324 throw utils::FatalError(
"Pass not found: " + std::string{name});
329 friend class HeapRef;
330 CustomBufferResource* newHeap(Pass& pass);
331 void freeHeap(Heap& heap);
332 void addDependency(
Pass& pass,
Pass& depends) {
333 depgraph_[&depends].push_back(&pass);
338 std::vector<std::unique_ptr<Pass>> passes_;
339 std::vector<Heap> heaps_;
340 std::unordered_map<Pass*, std::vector<Pass*>> depgraph_;
342 Pass* lastRun_ =
nullptr;
343 std::unordered_map<Pass*,
int> passDeps_;
348 template <
typename T>
351 return PM().getPass<T>(*
this);
354 template <
typename T>
356 Generator<T*> Pass::GetPasses() {
357 return PM().getPasses<T>(*
this);
363 #define REGISTER_PASS_NS(NS, T)
364 utils::Pass& New##T(utils::PassManager& PM) { return PM.AddPass<NS::T>(); }
369 #define REGISTER_PASS(T)
370 utils::Pass& New##T(utils::PassManager& PM) { return PM.AddPass<T>(); }
372 #define DECLARE_PASS(T) utils::Pass& New##T(utils::PassManager& PM);