83 explicit profile_t(Visitor &);
88 profile_t(
const profile_t &) =
delete;
89 profile_t &operator=(
const profile_t &) =
delete;
90 profile_t &operator=(profile_t &&) =
delete;
93 profile_t(profile_t &&);
95 virtual ~Visitor() =
default;
100 const Visitor *called_by =
nullptr;
102 const Visitor &setCalledBy(
const Visitor *visitor) {
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);
278 inline bool isInContext(
const Context *&c)
const {
280 if (!c)
return false;
281 while ((c = c->parent))
282 if (c->node->is<T>())
return true;
286 inline bool isInContext()
const {
287 const Context *c = ctxt;
288 return isInContext<T>(c);
290 inline bool isInContext(
const IR::Node *n)
const {
291 for (
auto *c = ctxt; c; c = c->parent) {
292 if (c->node == n || c->original == n)
return true;
303 return ctxt->node ? ctxt->node->
to<T>() : nullptr;
313 template <
class T,
typename = std::enable_if_t<Util::has_SourceInfo_v<T>>,
class... Args>
314 void warn(
const int kind,
const char *format,
const T *node, Args &&...args) {
320 typename = std::enable_if_t<Util::has_SourceInfo_v<T> && !std::is_pointer_v<T>>,
322 void warn(
const int kind,
const char *format,
const T &node, Args &&...args) {
331 bool visitDagOnce =
true;
332 bool dontForwardChildrenBeforePreorder =
false;
336 bool joinFlows =
false;
338 virtual void init_join_flows(
const IR::Node *) {
339 BUG(
"joinFlows only supported in ControlFlowVisitor currently");
367 void visit_children(
const IR::Node *, std::function<
void()> fn) { fn(); }
373 virtual void visitOnce()
const { BUG(
"do not know how to handle request"); }
374 virtual void visitAgain()
const { BUG(
"do not know how to handle request"); }
377 virtual void visitor_const_error();
378 const Context *ctxt =
nullptr;
379 friend class Inspector;
380 friend class Modifier;
381 friend class Transform;
382 friend class ControlFlowVisitor;
476class ControlFlowVisitor :
public virtual Visitor {
477 std::shared_ptr<std::map<cstring, ControlFlowVisitor &>> globals;
480 ControlFlowVisitor *clone()
const override = 0;
482 ControlFlowVisitor *vclone =
nullptr;
487 int exist = 0, visited = 0;
489 std::map<const IR::Node *, ctrs_t> parents;
492 typedef std::map<const IR::Node *, flow_join_info_t> flow_join_points_t;
494 friend std::ostream &operator<<(std::ostream &,
const flow_join_points_t &);
497 friend void dump(
const flow_join_points_t &);
498 friend void dump(
const flow_join_points_t *);
503 bool unreachable =
false;
505 flow_join_points_t *flow_join_points = 0;
506 class SetupJoinPoints :
public Inspector {
508 flow_join_points_t &join_points;
509 bool preorder(
const IR::Node *n)
override {
510 BUG_CHECK(join_points.count(n) == 0,
"oops");
512 auto *ctxt = getContext();
513 join_points[n].parents[ctxt ? ctxt->original :
nullptr].exist++;
517 void revisit(
const IR::Node *n)
override {
518 ++join_points[n].count;
520 auto *ctxt = getContext();
521 join_points[n].parents[ctxt ? ctxt->original :
nullptr].exist++;
526 explicit SetupJoinPoints(flow_join_points_t &fjp) : join_points(fjp) {}
528 bool BackwardsCompatibleBroken =
false;
531 virtual void applySetupJoinPoints(
const IR::Node *root) {
534 void init_join_flows(
const IR::Node *root)
override;
547 ControlFlowVisitor *controlFlowVisitor()
override {
return this; }
548 ControlFlowVisitor &flow_clone()
override;
550 virtual void flow_copy(ControlFlowVisitor &) = 0;
551 virtual bool operator==(
const ControlFlowVisitor &)
const {
552 BUG(
"%s pass does not support loops", name());
555 void setUnreachable() { unreachable =
true; }
556 bool isUnreachable() {
return unreachable; }
558 if (
auto other = globals->find(key); other != globals->end())
559 other->second.flow_merge(*
this);
561 globals->emplace(key, flow_clone());
563 void flow_merge_global_from(
cstring key)
override {
564 if (
auto other = globals->find(key); other != globals->end())
flow_merge(other->second);
566 void erase_global(cstring key)
override { globals->erase(key); }
567 bool check_global(cstring key)
override {
return globals->count(key) != 0; }
568 void clear_globals()
override { globals->clear(); }
569 std::pair<cstring, ControlFlowVisitor *> save_global(cstring key) {
570 ControlFlowVisitor *cfv =
nullptr;
571 if (
auto i = globals->find(key); i != globals->end()) {
575 return std::make_pair(key, cfv);
577 void restore_global(std::pair<cstring, ControlFlowVisitor *> saved) {
578 globals->erase(saved.first);
579 if (saved.second) globals->emplace(saved.first, *saved.second);
588 GuardGlobal(Visitor &self,
cstring key) : self(self), key(key) {
589 BUG_CHECK(!self.check_global(key),
"ControlFlowVisitor global %s in use", key);
591 ~GuardGlobal() { self.erase_global(key); }
595 ControlFlowVisitor &self;
596 std::vector<std::pair<cstring, ControlFlowVisitor *>> saved;
599 SaveGlobal(ControlFlowVisitor &self,
cstring key) : self(self) {
600 saved.push_back(self.save_global(key));
602 SaveGlobal(ControlFlowVisitor &self,
cstring k1,
cstring k2) : self(self) {
603 saved.push_back(self.save_global(k1));
604 saved.push_back(self.save_global(k2));
607 for (
auto it = saved.rbegin(); it != saved.rend(); ++it) self.restore_global(*it);
611 bool has_flow_joins()
const override {
return !!flow_join_points; }
612 const flow_join_info_t *flow_join_status(
const IR::Node *n)
const {
613 if (!flow_join_points || !flow_join_points->count(n))
return nullptr;
614 return &flow_join_points->at(n);
626class SplitFlowVisit_base {
629 SplitFlowVisit_base *prev;
630 std::vector<Visitor *> visitors;
631 int visit_next = 0, start_index = 0;
633 friend ControlFlowVisitor;
635 explicit SplitFlowVisit_base(
Visitor &v) : v(v) {
639 ~SplitFlowVisit_base() { v.split_link = prev; }
640 void *
operator new(size_t);
645 bool finished() {
return size_t(visit_next) >= visitors.size(); }
646 virtual bool ready() {
return !finished() && !paused; }
647 void pause() { paused =
true; }
648 void unpause() { paused =
false; }
649 virtual void do_visit() = 0;
650 virtual void run_visit() {
651 auto *ctxt = v.getChildContext();
652 start_index = ctxt ? ctxt->child_index : 0;
654 while (!finished()) do_visit();
655 for (
auto *cl : visitors) {
656 if (cl && cl != &v) v.flow_merge(*cl);
659 virtual void dbprint(std::ostream &)
const = 0;
660 friend void dump(
const SplitFlowVisit_base *);
664class SplitFlowVisit :
public SplitFlowVisit_base {
665 std::vector<const N **> nodes;
666 std::vector<const N *const *> const_nodes;
669 explicit SplitFlowVisit(
Visitor &v) : SplitFlowVisit_base(v) {}
670 void addNode(
const N *&node) {
671 BUG_CHECK(const_nodes.empty(),
"Mixing const and non-const in SplitFlowVisit");
672 BUG_CHECK(visitors.size() == nodes.size(),
"size mismatch in SplitFlowVisit");
673 BUG_CHECK(visit_next == 0,
"Can't addNode to SplitFlowVisit after visiting started");
674 visitors.push_back(visitors.empty() ? &v : &v.flow_clone());
675 nodes.emplace_back(&node);
677 void addNode(
const N *
const &node) {
678 BUG_CHECK(nodes.empty(),
"Mixing const and non-const in SplitFlowVisit");
679 BUG_CHECK(visitors.size() == const_nodes.size(),
"size mismatch in SplitFlowVisit");
680 BUG_CHECK(visit_next == 0,
"Can't addNode to SplitFlowVisit after visiting started");
681 visitors.push_back(visitors.empty() ? &v : &v.flow_clone());
682 const_nodes.emplace_back(&node);
684 template <
class T1,
class T2,
class... Args>
685 void addNode(T1 &&t1, T2 &&t2, Args &&...args) {
686 addNode(std::forward<T1>(t1));
687 addNode(std::forward<T2>(t2), std::forward<Args>(args)...);
689 template <
class... Args>
690 explicit SplitFlowVisit(
Visitor &v, Args &&...args) : SplitFlowVisit(v) {
691 addNode(std::forward<Args>(args)...);
693 void do_visit()
override {
695 BUG_CHECK(!paused,
"trying to visit paused split_flow_visitor");
696 int idx = visit_next++;
698 visitors.at(idx)->visit(*const_nodes.at(idx),
nullptr, start_index + idx);
700 visitors.at(idx)->visit(*nodes.at(idx),
nullptr, start_index + idx);
703 void dbprint(std::ostream &out)
const override {
704 out <<
"SplitFlowVisit processed " << visit_next <<
" of " << visitors.size();
709class SplitFlowVisitVector :
public SplitFlowVisit_base {
712 std::vector<const IR::Node *> result;
713 void init_visit(
size_t size) {
714 if (size > 0) visitors.push_back(&v);
715 while (visitors.size() < size) visitors.push_back(&v.flow_clone());
720 result.resize(vec.size());
721 init_visit(vec.size());
724 : SplitFlowVisit_base(v), const_vec(&vec) {
725 init_visit(vec.size());
727 void do_visit()
override {
729 BUG_CHECK(!paused,
"trying to visit paused split_flow_visitor");
730 int idx = visit_next++;
732 result[idx] = visitors.at(idx)->apply_visitor(vec->at(idx));
734 visitors.at(idx)->visit(const_vec->at(idx),
nullptr, start_index + idx);
737 void run_visit()
override {
738 SplitFlowVisit_base::run_visit();
741 for (
auto i = vec->begin(); i != vec->end(); ++idx) {
742 if (!result[idx] && *i) {
744 }
else if (result[idx] == *i) {
746 }
else if (
auto l = result[idx]->
template to<
IR::Vector<N>>()) {
748 i = vec->insert(i, l->begin(), l->end());
750 }
else if (
auto v = result[idx]->
template to<IR::VectorBase>()) {
754 i = vec->insert(i, v->size() - 1,
nullptr);
757 if (
auto e = el->template to<N>())
760 BUG(
"visitor returned invalid type %s for Vector<%s>",
761 el->node_type_name(), N::static_type_name());
764 }
else if (
auto e = result[idx]->
template to<N>()) {
767 CHECK_NULL(result[idx]);
768 BUG(
"visitor returned invalid type %s for Vector<%s>",
769 result[idx]->node_type_name(), N::static_type_name());
774 void dbprint(std::ostream &out)
const override {
775 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:122