100 const Visitor *called_by =
nullptr;
111 virtual profile_t init_apply(
const IR::Node *root);
112 profile_t init_apply(
const IR::Node *root,
const Context *parent_context);
117 virtual void end_apply();
118 virtual void end_apply(
const IR::Node *root);
123 virtual const IR::Node *apply_visitor(
const IR::Node *n,
const char *name = 0) = 0;
124 void visit(
const IR::Node *&n,
const char *name = 0) { n = apply_visitor(n, name); }
125 void visit(
const IR::Node *
const &n,
const char *name = 0) {
126 auto t = apply_visitor(n, name);
127 if (t != n) visitor_const_error();
129 void visit(
const IR::Node *&n,
const char *name,
int cidx) {
130 ctxt->child_index = cidx;
131 n = apply_visitor(n, name);
133 void visit(
const IR::Node *
const &n,
const char *name,
int cidx) {
134 ctxt->child_index = cidx;
135 auto t = apply_visitor(n, name);
136 if (t != n) visitor_const_error();
138 void visit(IR::Node *&,
const char * = 0,
int = 0) { BUG(
"Can't visit non-const pointer"); }
139#define DECLARE_VISIT_FUNCTIONS(CLASS, BASE) \
140 void visit(const IR::CLASS *&n, const char *name = 0); \
141 void visit(const IR::CLASS *const &n, const char *name = 0); \
142 void visit(const IR::CLASS *&n, const char *name, int cidx); \
143 void visit(const IR::CLASS *const &n, const char *name, int cidx); \
144 void visit(IR::CLASS *&, const char * = 0, int = 0) { BUG("Can't visit non-const pointer"); }
145 IRNODE_ALL_SUBCLASSES(DECLARE_VISIT_FUNCTIONS)
146#undef DECLARE_VISIT_FUNCTIONS
147 void visit(IR::Node &n,
const char *name = 0) {
148 if (name && ctxt) ctxt->child_name = name;
149 n.visit_children(*
this);
151 void visit(
const IR::Node &n,
const char *name = 0) {
152 if (name && ctxt) ctxt->child_name = name;
153 n.visit_children(*
this);
155 void visit(IR::Node &n,
const char *name,
int cidx) {
157 ctxt->child_name = name;
158 ctxt->child_index = cidx;
160 n.visit_children(*
this);
162 void visit(
const IR::Node &n,
const char *name,
int cidx) {
164 ctxt->child_name = name;
165 ctxt->child_index = cidx;
167 n.visit_children(*
this);
170 void parallel_visit(IR::Vector<T> &v,
const char *name = 0) {
171 if (name && ctxt) ctxt->child_name = name;
172 v.parallel_visit_children(*
this);
175 void parallel_visit(
const IR::Vector<T> &v,
const char *name = 0) {
176 if (name && ctxt) ctxt->child_name = name;
177 v.parallel_visit_children(*
this);
180 void parallel_visit(IR::Vector<T> &v,
const char *name,
int cidx) {
182 ctxt->child_name = name;
183 ctxt->child_index = cidx;
185 v.parallel_visit_children(*
this);
188 void parallel_visit(
const IR::Vector<T> &v,
const char *name,
int cidx) {
190 ctxt->child_name = name;
191 ctxt->child_index = cidx;
193 v.parallel_visit_children(*
this);
196 virtual Visitor *clone()
const {
197 BUG(
"need %s::clone method", name());
200 virtual bool check_clone(
const Visitor *a) {
return typeid(*this) ==
typeid(*a); }
203 virtual ControlFlowVisitor *controlFlowVisitor() {
return nullptr; }
204 virtual Visitor &flow_clone() {
return *
this; }
206 SplitFlowVisit_base *split_link_mem =
nullptr, *&split_link;
207 Visitor() : split_link(split_link_mem) {}
213 virtual bool flow_merge_closure(
Visitor &) { BUG(
"%s pass does not support loops", name()); }
216 virtual void flow_merge_global_from(
cstring) {}
217 virtual void erase_global(cstring) {}
218 virtual bool check_global(cstring) {
return false; }
219 virtual void clear_globals() {}
220 virtual bool has_flow_joins()
const {
return false; }
222 static cstring demangle(
const char *);
223 virtual const char *name()
const {
224 if (!internalName) internalName = demangle(
typeid(*this).name());
225 return internalName.c_str();
227 void setName(
const char *name) { internalName = cstring(name); }
228 void print_context()
const;
235 const IR::Node *getOriginal()
const {
return ctxt->original; }
237 const T *getOriginal()
const {
238 CHECK_NULL(ctxt->original);
239 BUG_CHECK(ctxt->original->
is<T>(),
"%1% does not have the expected type %2%",
240 ctxt->original, demangle(
typeid(T).name()));
241 return ctxt->original->
to<T>();
243 const Context *getChildContext()
const {
return ctxt; }
244 const Context *getContext()
const {
return ctxt->parent; }
246 const T *getParent()
const {
247 return ctxt->parent ? ctxt->parent->node->
to<T>() : nullptr;
249 int getChildrenVisited()
const {
return ctxt->child_index; }
250 int getContextDepth()
const {
return ctxt->depth - 1; }
252 inline const T *findContext(
const Context *&c)
const {
254 if (!c)
return nullptr;
255 while ((c = c->parent))
256 if (
auto *rv = c->node->to<T>())
return rv;
260 inline const T *findContext()
const {
261 const Context *c = ctxt;
262 return findContext<T>(c);
265 inline const T *findOrigCtxt(
const Context *&c)
const {
267 if (!c)
return nullptr;
268 while ((c = c->parent))
269 if (
auto *rv = c->original->to<T>())
return rv;
273 inline const T *findOrigCtxt()
const {
274 const Context *c = ctxt;
275 return findOrigCtxt<T>(c);
277 inline bool isInContext(
const IR::Node *n)
const {
278 for (
auto *c = ctxt; c; c = c->parent) {
279 if (c->node == n || c->original == n)
return true;
290 return ctxt->node ? ctxt->node->
to<T>() : nullptr;
300 template <
class T,
typename = std::enable_if_t<Util::has_SourceInfo_v<T>>,
class... Args>
301 void warn(
const int kind,
const char *format,
const T *node, Args &&...args) {
307 typename = std::enable_if_t<Util::has_SourceInfo_v<T> && !std::is_pointer_v<T>>,
309 void warn(
const int kind,
const char *format,
const T &node, Args &&...args) {
318 bool visitDagOnce =
true;
319 bool dontForwardChildrenBeforePreorder =
false;
323 bool joinFlows =
false;
325 virtual void init_join_flows(
const IR::Node *) {
326 BUG(
"joinFlows only supported in ControlFlowVisitor currently");
354 void visit_children(
const IR::Node *, std::function<
void()> fn) { fn(); }
360 virtual void visitOnce()
const { BUG(
"do not know how to handle request"); }
361 virtual void visitAgain()
const { BUG(
"do not know how to handle request"); }
364 virtual void visitor_const_error();
365 const Context *ctxt =
nullptr;
366 friend class Inspector;
367 friend class Modifier;
368 friend class Transform;
369 friend class ControlFlowVisitor;
464 std::shared_ptr<std::map<cstring, ControlFlowVisitor &>> globals;
474 int exist = 0, visited = 0;
476 std::map<const IR::Node *, ctrs_t> parents;
479 typedef std::map<const IR::Node *, flow_join_info_t> flow_join_points_t;
481 friend std::ostream &operator<<(std::ostream &,
const flow_join_points_t &);
484 friend void dump(
const flow_join_points_t &);
485 friend void dump(
const flow_join_points_t *);
490 bool unreachable =
false;
492 flow_join_points_t *flow_join_points = 0;
495 flow_join_points_t &join_points;
496 bool preorder(
const IR::Node *n)
override {
497 BUG_CHECK(join_points.count(n) == 0,
"oops");
499 auto *ctxt = getContext();
500 join_points[n].parents[ctxt ? ctxt->original :
nullptr].exist++;
504 void revisit(
const IR::Node *n)
override {
505 ++join_points[n].count;
507 auto *ctxt = getContext();
508 join_points[n].parents[ctxt ? ctxt->original :
nullptr].exist++;
513 explicit SetupJoinPoints(flow_join_points_t &fjp) : join_points(fjp) {}
515 bool BackwardsCompatibleBroken =
false;
518 virtual void applySetupJoinPoints(
const IR::Node *root) {
521 void init_join_flows(
const IR::Node *root)
override;
534 ControlFlowVisitor *controlFlowVisitor()
override {
return this; }
535 ControlFlowVisitor &flow_clone()
override;
539 BUG(
"%s pass does not support loops", name());
542 void setUnreachable() { unreachable =
true; }
543 bool isUnreachable() {
return unreachable; }
545 if (
auto other = globals->find(key); other != globals->end())
546 other->second.flow_merge(*
this);
548 globals->emplace(key, flow_clone());
550 void flow_merge_global_from(
cstring key)
override {
551 if (
auto other = globals->find(key); other != globals->end())
flow_merge(other->second);
553 void erase_global(cstring key)
override { globals->erase(key); }
554 bool check_global(cstring key)
override {
return globals->count(key) != 0; }
555 void clear_globals()
override { globals->clear(); }
556 std::pair<cstring, ControlFlowVisitor *> save_global(cstring key) {
557 ControlFlowVisitor *cfv =
nullptr;
558 if (
auto i = globals->find(key); i != globals->end()) {
562 return std::make_pair(key, cfv);
564 void restore_global(std::pair<cstring, ControlFlowVisitor *> saved) {
565 globals->erase(saved.first);
566 if (saved.second) globals->emplace(saved.first, *saved.second);
576 BUG_CHECK(!self.check_global(key),
"ControlFlowVisitor global %s in use", key);
583 std::vector<std::pair<cstring, ControlFlowVisitor *>> saved;
587 saved.push_back(self.save_global(key));
590 saved.push_back(self.save_global(k1));
591 saved.push_back(self.save_global(k2));
594 for (
auto it = saved.rbegin(); it != saved.rend(); ++it) self.restore_global(*it);
598 bool has_flow_joins()
const override {
return !!flow_join_points; }
599 const flow_join_info_t *flow_join_status(
const IR::Node *n)
const {
600 if (!flow_join_points || !flow_join_points->count(n))
return nullptr;
601 return &flow_join_points->at(n);
617 std::vector<Visitor *> visitors;
618 int visit_next = 0, start_index = 0;
627 void *
operator new(size_t);
632 bool finished() {
return size_t(visit_next) >= visitors.size(); }
633 virtual bool ready() {
return !finished() && !paused; }
634 void pause() { paused =
true; }
635 void unpause() { paused =
false; }
636 virtual void do_visit() = 0;
637 virtual void run_visit() {
638 auto *ctxt = v.getChildContext();
639 start_index = ctxt ? ctxt->child_index : 0;
641 while (!finished()) do_visit();
642 for (
auto *cl : visitors) {
646 virtual void dbprint(std::ostream &)
const = 0;
652 std::vector<const N **> nodes;
653 std::vector<const N *const *> const_nodes;
657 void addNode(
const N *&node) {
658 BUG_CHECK(const_nodes.empty(),
"Mixing const and non-const in SplitFlowVisit");
659 BUG_CHECK(visitors.size() == nodes.size(),
"size mismatch in SplitFlowVisit");
660 BUG_CHECK(visit_next == 0,
"Can't addNode to SplitFlowVisit after visiting started");
661 visitors.push_back(visitors.empty() ? &v : &v.flow_clone());
662 nodes.emplace_back(&node);
664 void addNode(
const N *
const &node) {
665 BUG_CHECK(nodes.empty(),
"Mixing const and non-const in SplitFlowVisit");
666 BUG_CHECK(visitors.size() == const_nodes.size(),
"size mismatch in SplitFlowVisit");
667 BUG_CHECK(visit_next == 0,
"Can't addNode to SplitFlowVisit after visiting started");
668 visitors.push_back(visitors.empty() ? &v : &v.flow_clone());
669 const_nodes.emplace_back(&node);
671 template <
class T1,
class T2,
class... Args>
672 void addNode(T1 &&t1, T2 &&t2, Args &&...args) {
673 addNode(std::forward<T1>(t1));
674 addNode(std::forward<T2>(t2), std::forward<Args>(args)...);
676 template <
class... Args>
678 addNode(std::forward<Args>(args)...);
680 void do_visit()
override {
682 BUG_CHECK(!paused,
"trying to visit paused split_flow_visitor");
683 int idx = visit_next++;
685 visitors.at(idx)->visit(*const_nodes.at(idx),
nullptr, start_index + idx);
687 visitors.at(idx)->visit(*nodes.at(idx),
nullptr, start_index + idx);
690 void dbprint(std::ostream &out)
const override {
691 out <<
"SplitFlowVisit processed " << visit_next <<
" of " << visitors.size();
699 std::vector<const IR::Node *> result;
700 void init_visit(
size_t size) {
701 if (size > 0) visitors.push_back(&v);
702 while (visitors.size() < size) visitors.push_back(&v.flow_clone());
707 result.resize(vec.size());
708 init_visit(vec.size());
712 init_visit(vec.size());
714 void do_visit()
override {
716 BUG_CHECK(!paused,
"trying to visit paused split_flow_visitor");
717 int idx = visit_next++;
719 result[idx] = visitors.at(idx)->apply_visitor(vec->at(idx));
721 visitors.at(idx)->visit(const_vec->at(idx),
nullptr, start_index + idx);
724 void run_visit()
override {
725 SplitFlowVisit_base::run_visit();
728 for (
auto i = vec->begin(); i != vec->end(); ++idx) {
729 if (!result[idx] && *i) {
731 }
else if (result[idx] == *i) {
733 }
else if (
auto l = result[idx]->
template to<
IR::Vector<N>>()) {
735 i = vec->insert(i, l->begin(), l->end());
737 }
else if (
auto v = result[idx]->
template to<IR::VectorBase>()) {
741 i = vec->insert(i, v->size() - 1,
nullptr);
744 if (
auto e = el->template to<N>())
747 BUG(
"visitor returned invalid type %s for Vector<%s>",
748 el->node_type_name(), N::static_type_name());
751 }
else if (
auto e = result[idx]->
template to<N>()) {
754 CHECK_NULL(result[idx]);
755 BUG(
"visitor returned invalid type %s for Vector<%s>",
756 result[idx]->node_type_name(), N::static_type_name());
761 void dbprint(std::ostream &out)
const override {
762 out <<
"SplitFlowVisitVector processed " << visit_next <<
" of " << visitors.size();
void warn(const int kind, const char *format, const T &node, Args &&...args)
The const ref variant of the above.
Definition visitor.h:309
void warning(const char *format, Args &&...args)
Report a warning with the given message.
Definition lib/error.h:115