74 explicit profile_t(Visitor &);
79 profile_t(
const profile_t &) =
delete;
80 profile_t &operator=(
const profile_t &) =
delete;
81 profile_t &operator=(profile_t &&) =
delete;
84 profile_t(profile_t &&);
86 virtual ~Visitor() =
default;
91 const Visitor *called_by =
nullptr;
93 const Visitor &setCalledBy(
const Visitor *visitor) {
102 virtual profile_t init_apply(
const IR::Node *root);
103 profile_t init_apply(
const IR::Node *root,
const Context *parent_context);
108 virtual void end_apply();
109 virtual void end_apply(
const IR::Node *root);
114 virtual const IR::Node *apply_visitor(
const IR::Node *n,
const char *name = 0) = 0;
115 void visit(
const IR::Node *&n,
const char *name = 0) { n = apply_visitor(n, name); }
116 void visit(
const IR::Node *
const &n,
const char *name = 0) {
117 auto t = apply_visitor(n, name);
118 if (t != n) visitor_const_error();
120 void visit(
const IR::Node *&n,
const char *name,
int cidx) {
121 ctxt->child_index = cidx;
122 n = apply_visitor(n, name);
124 void visit(
const IR::Node *
const &n,
const char *name,
int cidx) {
125 ctxt->child_index = cidx;
126 auto t = apply_visitor(n, name);
127 if (t != n) visitor_const_error();
129 void visit(IR::Node *&,
const char * = 0,
int = 0) { BUG(
"Can't visit non-const pointer"); }
130#define DECLARE_VISIT_FUNCTIONS(CLASS, BASE) \
131 void visit(const IR::CLASS *&n, const char *name = 0); \
132 void visit(const IR::CLASS *const &n, const char *name = 0); \
133 void visit(const IR::CLASS *&n, const char *name, int cidx); \
134 void visit(const IR::CLASS *const &n, const char *name, int cidx); \
135 void visit(IR::CLASS *&, const char * = 0, int = 0) { BUG("Can't visit non-const pointer"); }
136 IRNODE_ALL_SUBCLASSES(DECLARE_VISIT_FUNCTIONS)
137#undef DECLARE_VISIT_FUNCTIONS
138 void visit(IR::Node &n,
const char *name = 0) {
139 if (ctxt) ctxt->child_name = name;
140 n.visit_children(*
this, name);
142 void visit(
const IR::Node &n,
const char *name = 0) {
143 if (ctxt) ctxt->child_name = name;
144 n.visit_children(*
this, name);
146 void visit(IR::Node &n,
const char *name,
int cidx) {
148 ctxt->child_name = name;
149 ctxt->child_index = cidx;
151 n.visit_children(*
this, name);
153 void visit(
const IR::Node &n,
const char *name,
int cidx) {
155 ctxt->child_name = name;
156 ctxt->child_index = cidx;
158 n.visit_children(*
this, name);
161 void parallel_visit(IR::Vector<T> &v,
const char *name = 0) {
162 if (name && ctxt) ctxt->child_name = name;
163 v.parallel_visit_children(*
this);
166 void parallel_visit(
const IR::Vector<T> &v,
const char *name = 0) {
167 if (name && ctxt) ctxt->child_name = name;
168 v.parallel_visit_children(*
this);
171 void parallel_visit(IR::Vector<T> &v,
const char *name,
int cidx) {
173 ctxt->child_name = name;
174 ctxt->child_index = cidx;
176 v.parallel_visit_children(*
this);
179 void parallel_visit(
const IR::Vector<T> &v,
const char *name,
int cidx) {
181 ctxt->child_name = name;
182 ctxt->child_index = cidx;
184 v.parallel_visit_children(*
this);
187 virtual Visitor *clone()
const {
188 BUG(
"need %s::clone method", name());
191 virtual bool check_clone(
const Visitor *a) {
return typeid(*this) ==
typeid(*a); }
194 virtual ControlFlowVisitor *controlFlowVisitor() {
return nullptr; }
195 virtual Visitor &flow_clone() {
return *
this; }
197 SplitFlowVisit_base *split_link_mem =
nullptr, *&split_link;
198 Visitor() : split_link(split_link_mem) {}
204 virtual bool flow_merge_closure(
Visitor &) { BUG(
"%s pass does not support loops", name()); }
207 virtual void flow_merge_global_from(
cstring) {}
208 virtual void erase_global(cstring) {}
209 virtual bool check_global(cstring) {
return false; }
210 virtual void clear_globals() {}
211 virtual bool has_flow_joins()
const {
return false; }
213 static cstring demangle(
const char *);
214 virtual const char *name()
const {
215 if (!internalName) internalName = demangle(
typeid(*this).name());
216 return internalName.c_str();
218 void setName(
const char *name) { internalName = cstring(name); }
219 void print_context()
const;
226 const IR::Node *getOriginal()
const {
return ctxt->original; }
228 const T *getOriginal()
const {
229 CHECK_NULL(ctxt->original);
230 BUG_CHECK(ctxt->original->is<T>(),
"%1% does not have the expected type %2%",
231 ctxt->original, demangle(
typeid(T).name()));
232 return ctxt->original->to<T>();
234 const Context *getChildContext()
const {
return ctxt; }
235 const Context *getContext()
const {
return ctxt->parent; }
237 const T *getParent()
const {
238 return ctxt->parent ? ctxt->parent->node->to<T>() : nullptr;
240 int getChildrenVisited()
const {
return ctxt->child_index; }
241 int getContextDepth()
const {
return ctxt->depth - 1; }
243 inline const T *findContext(
const Context *&c)
const {
245 if (!c)
return nullptr;
246 while ((c = c->parent))
247 if (
auto *rv = c->node->to<T>())
return rv;
251 inline const T *findContext()
const {
252 const Context *c = ctxt;
253 return findContext<T>(c);
256 inline const T *findOrigCtxt(
const Context *&c)
const {
258 if (!c)
return nullptr;
259 while ((c = c->parent))
260 if (
auto *rv = c->original->to<T>())
return rv;
264 inline const T *findOrigCtxt()
const {
265 const Context *c = ctxt;
266 return findOrigCtxt<T>(c);
269 inline bool isInContext(
const Context *&c)
const {
271 if (!c)
return false;
272 while ((c = c->parent))
273 if (c->node->is<T>())
return true;
277 inline bool isInContext()
const {
278 const Context *c = ctxt;
279 return isInContext<T>(c);
281 inline bool isInContext(
const IR::Node *n)
const {
282 for (
auto *c = ctxt; c; c = c->parent) {
283 if (c->node == n || c->original == n)
return true;
294 return ctxt->node ? ctxt->node->
to<T>() : nullptr;
304 template <
class T,
typename = std::enable_if_t<Util::has_SourceInfo_v<T>>,
class... Args>
305 void warn(
const int kind,
const char *format,
const T *node, Args &&...args) {
311 typename = std::enable_if_t<Util::has_SourceInfo_v<T> && !std::is_pointer_v<T>>,
313 void warn(
const int kind,
const char *format,
const T &node, Args &&...args) {
322 bool visitDagOnce =
true;
323 bool dontForwardChildrenBeforePreorder =
false;
327 bool joinFlows =
false;
329 virtual void init_join_flows(
const IR::Node *) {
330 BUG(
"joinFlows only supported in ControlFlowVisitor currently");
358 void visit_children(
const IR::Node *, std::function<
void()> fn) { fn(); }
364 virtual void visitOnce()
const { BUG(
"do not know how to handle request"); }
365 virtual void visitAgain()
const { BUG(
"do not know how to handle request"); }
368 virtual void visitor_const_error();
369 const Context *ctxt =
nullptr;
370 friend class Inspector;
371 friend class Modifier;
372 friend class Transform;
373 friend class ControlFlowVisitor;
477class ControlFlowVisitor :
public virtual Visitor {
478 std::shared_ptr<std::map<cstring, ControlFlowVisitor &>> globals;
481 ControlFlowVisitor *clone()
const override = 0;
483 ControlFlowVisitor *vclone =
nullptr;
488 int exist = 0, visited = 0;
490 std::map<const IR::Node *, ctrs_t> parents;
493 typedef std::map<const IR::Node *, flow_join_info_t> flow_join_points_t;
495 friend std::ostream &operator<<(std::ostream &,
const flow_join_points_t &);
498 friend void dump(
const flow_join_points_t &);
499 friend void dump(
const flow_join_points_t *);
504 bool unreachable =
false;
506 flow_join_points_t *flow_join_points = 0;
507 class SetupJoinPoints :
public Inspector {
509 flow_join_points_t &join_points;
510 bool preorder(
const IR::Node *n)
override {
511 BUG_CHECK(join_points.count(n) == 0,
"oops");
513 auto *ctxt = getContext();
514 join_points[n].parents[ctxt ? ctxt->original :
nullptr].exist++;
518 void revisit(
const IR::Node *n)
override {
519 ++join_points[n].count;
521 auto *ctxt = getContext();
522 join_points[n].parents[ctxt ? ctxt->original :
nullptr].exist++;
527 explicit SetupJoinPoints(flow_join_points_t &fjp) : join_points(fjp) {}
529 bool BackwardsCompatibleBroken =
false;
532 virtual void applySetupJoinPoints(
const IR::Node *root) {
535 void init_join_flows(
const IR::Node *root)
override;
548 ControlFlowVisitor *controlFlowVisitor()
override {
return this; }
549 ControlFlowVisitor &flow_clone()
override;
551 virtual void flow_copy(ControlFlowVisitor &) = 0;
552 virtual bool operator==(
const ControlFlowVisitor &)
const {
553 BUG(
"%s pass does not support loops", name());
556 void setUnreachable() { unreachable =
true; }
557 bool isUnreachable() {
return unreachable; }
559 if (
auto other = globals->find(key); other != globals->end())
560 other->second.flow_merge(*
this);
562 globals->emplace(key, flow_clone());
564 void flow_merge_global_from(
cstring key)
override {
565 if (
auto other = globals->find(key); other != globals->end())
flow_merge(other->second);
567 void erase_global(cstring key)
override { globals->erase(key); }
568 bool check_global(cstring key)
override {
return globals->count(key) != 0; }
569 void clear_globals()
override { globals->clear(); }
570 std::pair<cstring, ControlFlowVisitor *> save_global(cstring key) {
571 ControlFlowVisitor *cfv =
nullptr;
572 if (
auto i = globals->find(key); i != globals->end()) {
576 return std::make_pair(key, cfv);
578 void restore_global(std::pair<cstring, ControlFlowVisitor *> saved) {
579 globals->erase(saved.first);
580 if (saved.second) globals->emplace(saved.first, *saved.second);
589 GuardGlobal(Visitor &self,
cstring key) : self(self), key(key) {
590 BUG_CHECK(!self.check_global(key),
"ControlFlowVisitor global %s in use", key);
592 ~GuardGlobal() { self.erase_global(key); }
596 ControlFlowVisitor &self;
597 std::vector<std::pair<cstring, ControlFlowVisitor *>> saved;
600 SaveGlobal(ControlFlowVisitor &self,
cstring key) : self(self) {
601 saved.push_back(self.save_global(key));
603 SaveGlobal(ControlFlowVisitor &self,
cstring k1,
cstring k2) : self(self) {
604 saved.push_back(self.save_global(k1));
605 saved.push_back(self.save_global(k2));
608 for (
auto it = saved.rbegin(); it != saved.rend(); ++it) self.restore_global(*it);
612 bool has_flow_joins()
const override {
return !!flow_join_points; }
613 const flow_join_info_t *flow_join_status(
const IR::Node *n)
const {
614 if (!flow_join_points || !flow_join_points->count(n))
return nullptr;
615 return &flow_join_points->at(n);
627class SplitFlowVisit_base {
630 SplitFlowVisit_base *prev;
631 std::vector<Visitor *> visitors;
632 int visit_next = 0, start_index = 0;
634 friend ControlFlowVisitor;
636 explicit SplitFlowVisit_base(
Visitor &v) : v(v) {
640 ~SplitFlowVisit_base() { v.split_link = prev; }
641 void *
operator new(size_t);
646 bool finished() {
return size_t(visit_next) >= visitors.size(); }
647 virtual bool ready() {
return !finished() && !paused; }
648 void pause() { paused =
true; }
649 void unpause() { paused =
false; }
650 virtual void do_visit() = 0;
651 virtual void run_visit() {
652 auto *ctxt = v.getChildContext();
653 start_index = ctxt ? ctxt->child_index : 0;
655 while (!finished()) do_visit();
656 for (
auto *cl : visitors) {
657 if (cl && cl != &v) v.flow_merge(*cl);
660 virtual void dbprint(std::ostream &)
const = 0;
661 friend void dump(
const SplitFlowVisit_base *);
665class SplitFlowVisit :
public SplitFlowVisit_base {
666 std::vector<const N **> nodes;
667 std::vector<const N *const *> const_nodes;
670 explicit SplitFlowVisit(
Visitor &v) : SplitFlowVisit_base(v) {}
671 void addNode(
const N *&node) {
672 BUG_CHECK(const_nodes.empty(),
"Mixing const and non-const in SplitFlowVisit");
673 BUG_CHECK(visitors.size() == nodes.size(),
"size mismatch in SplitFlowVisit");
674 BUG_CHECK(visit_next == 0,
"Can't addNode to SplitFlowVisit after visiting started");
675 visitors.push_back(visitors.empty() ? &v : &v.flow_clone());
676 nodes.emplace_back(&node);
678 void addNode(
const N *
const &node) {
679 BUG_CHECK(nodes.empty(),
"Mixing const and non-const in SplitFlowVisit");
680 BUG_CHECK(visitors.size() == const_nodes.size(),
"size mismatch in SplitFlowVisit");
681 BUG_CHECK(visit_next == 0,
"Can't addNode to SplitFlowVisit after visiting started");
682 visitors.push_back(visitors.empty() ? &v : &v.flow_clone());
683 const_nodes.emplace_back(&node);
685 template <
class T1,
class T2,
class... Args>
686 void addNode(T1 &&t1, T2 &&t2, Args &&...args) {
687 addNode(std::forward<T1>(t1));
688 addNode(std::forward<T2>(t2), std::forward<Args>(args)...);
690 template <
class... Args>
691 explicit SplitFlowVisit(
Visitor &v, Args &&...args) : SplitFlowVisit(v) {
692 addNode(std::forward<Args>(args)...);
694 void do_visit()
override {
696 BUG_CHECK(!paused,
"trying to visit paused split_flow_visitor");
697 int idx = visit_next++;
699 visitors.at(idx)->visit(*const_nodes.at(idx),
nullptr, start_index + idx);
701 visitors.at(idx)->visit(*nodes.at(idx),
nullptr, start_index + idx);
704 void dbprint(std::ostream &out)
const override {
705 out <<
"SplitFlowVisit processed " << visit_next <<
" of " << visitors.size();
710class SplitFlowVisitVector :
public SplitFlowVisit_base {
713 std::vector<const IR::Node *> result;
714 void init_visit(
size_t size) {
715 if (size > 0) visitors.push_back(&v);
716 while (visitors.size() < size) visitors.push_back(&v.flow_clone());
721 result.resize(vec.size());
722 init_visit(vec.size());
725 : SplitFlowVisit_base(v), const_vec(&vec) {
726 init_visit(vec.size());
728 void do_visit()
override {
730 BUG_CHECK(!paused,
"trying to visit paused split_flow_visitor");
731 int idx = visit_next++;
733 result[idx] = visitors.at(idx)->apply_visitor(vec->at(idx));
735 visitors.at(idx)->visit(const_vec->at(idx),
nullptr, start_index + idx);
738 void run_visit()
override {
739 SplitFlowVisit_base::run_visit();
742 for (
auto i = vec->begin(); i != vec->end(); ++idx) {
743 if (!result[idx] && *i) {
745 }
else if (result[idx] == *i) {
747 }
else if (
auto l = result[idx]->
template to<
IR::Vector<N>>()) {
749 i = vec->insert(i, l->begin(), l->end());
751 }
else if (
auto v = result[idx]->
template to<IR::VectorBase>()) {
755 i = vec->insert(i, v->size() - 1,
nullptr);
758 if (
auto e = el->template to<N>())
761 BUG(
"visitor returned invalid type %s for Vector<%s>",
762 el->node_type_name(), N::static_type_name());
765 }
else if (
auto e = result[idx]->
template to<N>()) {
768 CHECK_NULL(result[idx]);
769 BUG(
"visitor returned invalid type %s for Vector<%s>",
770 result[idx]->node_type_name(), N::static_type_name());
775 void dbprint(std::ostream &out)
const override {
776 out <<
"SplitFlowVisitVector processed " << visit_next <<
" of " << visitors.size();
void warning(const char *format, Args &&...args)
Report a warning with the given message.
Definition lib/error.h:119