15struct NullSafeDefGIDLt {
16 constexpr bool operator()(
const Def* a,
const Def* b)
const noexcept {
17 return (a ?
a->gid() : 0) < (b ? b->gid() : 0);
33 const Node*
inest()
const {
return inest_; }
36 const Node*
idom()
const {
return idom_; }
37 bool is_root()
const {
return inest_ ==
nullptr; }
43 uint32_t
level()
const {
return level_; }
47 uint32_t
gid()
const {
return mut_ ? mut_->gid() : 0; }
56 auto muts()
const {
return mut2node_ | std::views::keys; }
57 auto nodes()
const {
return mut2node_ | std::views::transform([](
auto p) {
return const_cast<const Node*
>(p.second); }); }
59 size_t num()
const {
return mut2node_.size(); }
70 auto begin()
const {
return mut2node_.cbegin(); }
71 auto end()
const {
return mut2node_.cend(); }
75 auto mut_nodes() {
return mut2node_ | std::views::values; }
89 return nodes_ | std::views::transform([](Node* n) {
return const_cast<const Node*
>(n); });
95 size_t num()
const {
return nodes_.size(); }
96 bool contains(
const Node* n)
const {
return nodes_.contains(
const_cast<Node*
>(n)); }
101 auto begin()
const {
return nodes_.cbegin(); }
102 auto end()
const {
return nodes_.cend(); }
115 template<
bool Forward = true>
117 if constexpr (Forward)
120 return sibl_rev_deps_;
150 void link(
Node* other) { this->sibl_deps_.nodes_.emplace(other), other->sibl_rev_deps_.nodes_.emplace(
this); }
151 void dot(fe::Tab, std::ostream&)
const;
153 using Stack = std::stack<Node*>;
154 uint32_t tarjan(uint32_t, Stack&);
160 uint32_t loop_depth_ : 31 = 0;
161 bool recursive_ : 1 =
false;
163 SiblDeps sibl_rev_deps_;
165 std::deque<std::unique_ptr<SCC>> topo_;
166 const SCC* scc_ =
nullptr;
167 const Node* idom_ =
nullptr;
170 std::optional<size_t> postorder_number_ = std::nullopt;
173 static constexpr uint32_t Unvisited = uint32_t(-1);
174 uint32_t idx_ = Unvisited;
175 uint32_t low_ : 31 = 0;
176 bool on_stack_ : 1 =
false;
204 auto muts()
const {
return mut2node_ | std::views::keys; }
205 auto nodes()
const {
return mut2node_ | std::views::transform([](
const auto& p) {
return (
const Node*)p.second.get(); }); }
216 auto begin()
const {
return mut2node_.cbegin(); }
217 auto end()
const {
return mut2node_.cend(); }
226 void dot(
const char* file =
nullptr, DotConfig cfg = {})
const;
231 Node* node(Def* mut)
const {
232 if (
auto i = mut2node_.find(mut); i != mut2node_.end())
return i->second.get();
236 Node* innermost(
const Def*)
const;
239 void populate(
bool transitive);
241 void calc_sibl_deps(
Node*, fe::Vector<Node*>& path);
242 void calc_SCCs(
Node*);
243 void number(
Node*,
size_t&);
244 void calc_dominance(
Node*);
245 void sibl_post_order(
Node*, ankerl::unordered_dense::set<const Node*>&, fe::Vector<Node*>&);
248 std::map<Def*, std::unique_ptr<Node>, detail::NullSafeDefGIDLt> mut2node_;
std::string unique_name() const
name + "_" + Def::gid
bool has_free_vars_in(Vars) const
Same as vars.has_intersection(free_vars()).
const Node * idom() const
Immediate Dominator for children in connected components; used for late code placement in [Nest::lca]...
const SiblDeps & sibl_deps() const
GIDSet< const Node * > SCC
Strongly Connected Component.
Def * mut() const
The mutable capsulated in this Node or nullptr, if it's a virtual root comprising several Nodes.
bool is_recursive() const
const Children & children() const
const SCC & scc() const
The SCC among its siblings this Node belongs to; the Nest::root() has none.
const Nest & nest() const
bool is_directly_recursive() const
bool is_mutually_recursive() const
uint32_t loop_depth() const
const Node * inest() const
Immediate nester/parent of this Node.
uint32_t gid() const
Stable id for deterministic hashing/ordering: the underlying mut's gid, or 0 for the (unique) virtual...
const Node * inest(const Def *def) const
The innermost Node binding a free Var of def, or the root() if there is none.
void dot(std::ostream &os, DotConfig cfg={}) const
bool is_recursive() const
void dot(std::string s, DotConfig cfg={}) const
const Node * operator[](Def *mut) const
Nest & operator=(Nest)=delete
static const Node * lca(const Node *n, const Node *m)
Least common ancestor of n and m.
const Node * root() const
Vars vars() const
All Vars occurring in this Nest.
Nest(const Nest &)=delete
bool contains(const Def *def) const
The World represents the whole program and manages creation of MimIR nodes (Defs).
ankerl::unordered_dense::set< K, GIDHash< K > > GIDSet
fe::Patricia< const Var, DefKey >::Set Vars
GIDMap< Def *, To > MutMap
Options for Def::dot, World::dot, and Nest::dot.
size_t num() const
Number of children.
bool contains(Def *mut) const
is mut a child?
const Node * operator[](Def *mut) const
bool contains(const Node *n) const