P4C
The P4 Compiler
Loading...
Searching...
No Matches
ir/pass_manager.h
1/*
2 * SPDX-FileCopyrightText: 2013 Barefoot Networks, Inc.
3 * Copyright 2013-present Barefoot Networks, Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef IR_PASS_MANAGER_H_
9#define IR_PASS_MANAGER_H_
10
11#include <functional>
12#include <initializer_list>
13#include <iosfwd>
14#include <type_traits>
15#include <vector>
16
17#include "ir/node.h"
18#include "ir/visitor.h"
19#include "lib/cstring.h"
20#include "lib/exceptions.h"
21#include "lib/safe_vector.h"
22
23namespace P4 {
24
27typedef std::function<void(const char *manager, unsigned seqNo, const char *pass,
28 const IR::Node *node)>
30
31class PassManager : virtual public Visitor, virtual public Backtrack {
32 bool early_exit_flag = false;
33 mutable int never_backtracks_cache = -1;
34
35 protected:
36 safe_vector<DebugHook> debugHooks; // called after each pass
38 // if true stops compilation after first pass that signals an error
39 bool stop_on_error = true;
40 bool running = false;
41 unsigned seqNo = 0;
42 void runDebugHooks(const char *visitorName, const IR::Node *node);
43 profile_t init_apply(const IR::Node *root) override {
44 running = true;
45 return Visitor::init_apply(root);
46 }
47
48 public:
49 PassManager() = default;
50 PassManager(const PassManager &) = default;
51 PassManager(PassManager &&) = default;
52 class VisitorRef {
53 Visitor *visitor;
54 friend class PassManager;
55
56 public:
57 VisitorRef() : visitor(nullptr) {}
58 VisitorRef(Visitor *v) : visitor(v) {} // NOLINT(runtime/explicit)
59 VisitorRef(const Visitor &v) : visitor(v.clone()) { // NOLINT(runtime/explicit)
60 BUG_CHECK(visitor->check_clone(&v), "Incorrect clone in PassManager");
61 }
62 explicit VisitorRef(std::function<const IR::Node *(const IR::Node *)>);
63 // ambiguity resolution converters -- allow different lambda signatures
64 template <class T>
65 VisitorRef(
66 T t,
67 typename std::enable_if<
68 std::is_convertible<decltype(t(nullptr)), const IR::Node *>::value, int>::type = 0)
69 : VisitorRef(std::function<const IR::Node *(const IR::Node *)>(t)) {}
70 template <class T>
71 VisitorRef(
72 T t,
73 typename std::enable_if<std::is_same<decltype(t(nullptr)), void>::value, int>::type = 0)
74 : VisitorRef(std::function<const IR::Node *(const IR::Node *)>(
75 [t](const IR::Node *n) -> const IR::Node * {
76 t(n);
77 return n;
78 })) {}
79 template <class T>
80 VisitorRef(T t,
81 typename std::enable_if<std::is_same<decltype(t()), void>::value, int>::type = 0)
82 : VisitorRef(std::function<const IR::Node *(const IR::Node *)>(
83 [t](const IR::Node *n) -> const IR::Node * {
84 t();
85 return n;
86 })) {}
87 };
88 PassManager(const std::initializer_list<VisitorRef> &init) { addPasses(init); }
89 void addPasses(const std::initializer_list<VisitorRef> &init) {
90 never_backtracks_cache = -1;
91 for (auto &p : init)
92 if (p.visitor) passes.emplace_back(p.visitor);
93 }
94 void removePasses(const std::vector<cstring> &exclude);
95 void listPasses(std::ostream &, cstring sep) const;
96 const IR::Node *apply_visitor(const IR::Node *, const char * = 0) override;
97 bool backtrack(trigger &trig) override;
98 bool never_backtracks() override;
99 void setStopOnError(bool stop) { stop_on_error = stop; }
100 void addDebugHook(DebugHook h, bool recursive = false) {
101 debugHooks.push_back(h);
102 if (recursive)
103 for (auto pass : passes)
104 if (auto child = dynamic_cast<PassManager *>(pass))
105 child->addDebugHook(h, recursive);
106 }
107 void addDebugHooks(std::vector<DebugHook> hooks, bool recursive = false) {
108 debugHooks.insert(debugHooks.end(), hooks.begin(), hooks.end());
109 if (recursive)
110 for (auto pass : passes)
111 if (auto child = dynamic_cast<PassManager *>(pass))
112 child->addDebugHooks(hooks, recursive);
113 }
114 void early_exit() { early_exit_flag = true; }
115 PassManager *clone() const override { return new PassManager(*this); }
116 auto getPasses() { return Util::iterator_range(passes); }
117};
118
119template <class T>
120class OnBacktrack : virtual public Visitor, virtual public Backtrack {
121 std::function<void(T *)> fn;
122
123 public:
124 explicit OnBacktrack(std::function<void(T *)> f) : fn(f) {}
125 const IR::Node *apply_visitor(const IR::Node *n, const char * = 0) override { return n; }
126 bool backtrack(trigger &trig) override {
127 if (auto *t = dynamic_cast<T *>(&trig)) {
128 fn(t);
129 return true;
130 } else {
131 return false;
132 }
133 }
134};
135
136// Repeat a pass until convergence (or up to a fixed number of repeats)
137class PassRepeated : virtual public PassManager {
138 unsigned repeats; // 0 = until convergence
139 public:
140 PassRepeated() : repeats(0) {}
141 explicit PassRepeated(const std::initializer_list<VisitorRef> &init, unsigned repeats = 0)
142 : PassManager(init), repeats(repeats) {}
143 explicit PassRepeated(const PassManager &other, unsigned repeats = 0)
144 : PassManager(other), repeats(repeats) {}
145 const IR::Node *apply_visitor(const IR::Node *, const char * = 0) override;
146 PassRepeated *setRepeats(unsigned repeats) {
147 this->repeats = repeats;
148 return this;
149 }
150 PassRepeated *clone() const override { return new PassRepeated(*this); }
151};
152
153class PassRepeatUntil : virtual public PassManager {
154 std::function<bool()> done;
155
156 public:
157 explicit PassRepeatUntil(std::function<bool()> done) : done(done) {}
158 PassRepeatUntil(const std::initializer_list<VisitorRef> &init, std::function<bool()> done)
159 : PassManager(init), done(done) {}
160 const IR::Node *apply_visitor(const IR::Node *, const char * = 0) override;
161 PassRepeatUntil *clone() const override { return new PassRepeatUntil(*this); }
162};
163
164class PassIf : virtual public PassManager {
165 std::function<bool()> cond;
166
167 public:
168 explicit PassIf(std::function<bool()> cond) : cond(cond) {}
169 PassIf(std::function<bool()> cond, const std::initializer_list<VisitorRef> &init)
170 : PassManager(init), cond(cond) {}
171 const IR::Node *apply_visitor(const IR::Node *, const char * = 0) override;
172 PassIf *clone() const override { return new PassIf(*this); }
173};
174
175// Converts a function Node* -> Node* into a visitor
176class VisitFunctor : virtual public Visitor {
177 std::function<const IR::Node *(const IR::Node *)> fn;
178 const IR::Node *apply_visitor(const IR::Node *n, const char * = 0) override { return fn(n); }
179
180 public:
181 explicit VisitFunctor(std::function<const IR::Node *(const IR::Node *)> f) : fn(f) {}
182 explicit VisitFunctor(std::function<void()> f)
183 : fn([f](const IR::Node *n) -> const IR::Node * {
184 f();
185 return n;
186 }) {}
187
188 VisitFunctor *clone() const override { return new VisitFunctor(*this); }
189};
190
191inline PassManager::VisitorRef::VisitorRef(std::function<const IR::Node *(const IR::Node *)> fn)
192 : visitor(new VisitFunctor(fn)) {}
193
194class DynamicVisitor : virtual public Visitor {
195 Visitor *visitor;
196 profile_t init_apply(const IR::Node *root) override {
197 if (visitor) return visitor->init_apply(root);
198 return Visitor::init_apply(root);
199 }
200 void end_apply(const IR::Node *root) override {
201 if (visitor) visitor->end_apply(root);
202 }
203 const IR::Node *apply_visitor(const IR::Node *root, const char *name = 0) override {
204 if (visitor) return visitor->apply_visitor(root, name);
205 return root;
206 }
207
208 public:
209 DynamicVisitor() : visitor(nullptr) {}
210 explicit DynamicVisitor(Visitor *v) : visitor(v) {}
211 void setVisitor(Visitor *v) { visitor = v; }
212 DynamicVisitor *clone() const override { return new DynamicVisitor(*this); }
213};
214
215} // namespace P4
216
217#endif /* IR_PASS_MANAGER_H_ */
Definition visitor.h:780
Definition node.h:44
Definition ir/pass_manager.h:176
Definition visitor.h:69
Definition safe_vector.h:18
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
std::function< void(const char *manager, unsigned seqNo, const char *pass, const IR::Node *node)> DebugHook
Definition ir/pass_manager.h:29
Definition visitor.h:782