20 bool is_root()
const {
return parent_ ==
nullptr; }
26 uint32_t
level()
const {
return level_; }
27 uint32_t
loop_depth()
const {
return sccs().loop_depth_; }
32 auto child_muts()
const {
return child_mut2node_ | std::views::keys; }
34 return child_mut2node_
35 | std::views::transform([](
const auto& pair) {
return const_cast<const Node*
>(pair.second); });
38 return child_mut2node_ | std::views::transform([](
const auto& pair) {
39 return std::pair{pair.first,
const_cast<const Node*
>(pair.second)};
43 if (
auto i = child_mut2node_.find(
mut); i != child_mut2node_.end())
return i->second;
55 return deps().depends_ | std::views::transform([](
Node* n) {
return const_cast<const Node*
>(n); });
58 return deps().controls_ | std::views::transform([](
Node* n) {
return const_cast<const Node*
>(n); });
64 using SCC = absl::flat_hash_set<const Node*>;
70 const auto&
SCCs() {
return sccs().SCCs_; }
71 const auto&
topo()
const {
return sccs().topo_; }
86 const Node& deps()
const {
return nest().deps(), *
this; }
87 const Node& sccs()
const {
return nest().sccs(), *
this; }
89 void link(Node* node) { this->depends_.emplace(node), node->controls_.emplace(
this); }
90 void dot(Tab, std::ostream&)
const;
93 using Stack = std::stack<Node*>;
95 uint32_t tarjan(uint32_t, Node*, Stack&);
101 uint32_t loop_depth_ : 31 = 0;
102 bool recursive_ : 1 =
false;
104 absl::flat_hash_set<Node*> depends_;
105 absl::flat_hash_set<Node*> controls_;
106 std::deque<std::unique_ptr<SCC>> topo_;
107 absl::node_hash_map<const Node*, const SCC*> SCCs_;
110 static constexpr uint32_t Unvisited = uint32_t(-1);
111 uint32_t idx_ = Unvisited;
112 uint32_t low_ : 31 = 0;
113 bool on_stack_ : 1 =
false;
114 Node* curr_child =
nullptr;
137 auto muts()
const {
return mut2node_ | std::views::keys; }
139 return mut2node_ | std::views::transform([](
const auto& pair) {
return (
const Node*)pair.second.get(); });
147 static const Node*
lca(
const Node* n,
const Node* m);
152 void dot(std::ostream& os)
const;
153 void dot(
const char* file =
nullptr)
const;
154 void dot(std::string s)
const {
dot(s.c_str()); }
158 Node* mut2node_nonconst(
Def* mut)
const {
159 if (
auto i = mut2node_.find(mut); i != mut2node_.end())
return i->second.get();
164 Node* make_node(Def*, Node* parent =
nullptr);
165 void deps(Node*)
const;
166 void find_SCCs(Node*)
const;
168 const Nest& deps()
const {
176 const Nest& sccs()
const {
185 absl::flat_hash_map<Def*, std::unique_ptr<Node>> mut2node_;
188 mutable bool deps_ =
false;
189 mutable bool sccs_ =
false;
std::string unique_name() const
name + "_" + Def::gid
Vars free_vars() const
Compute a global solution, i.e., by transitively following mutables as well.
size_t num_depends() const
auto child_mut2node() const
const Node * child(Def *mut) const
size_t num_children() const
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 Node * parent() const
absl::flat_hash_set< const Node * > SCC
Strongly Connected Component.
const auto & topo() const
Topological sorting of all SCCs.
const Nest & nest() const
bool is_directly_recursive() const
bool is_mutually_recursive() const
uint32_t loop_depth() const
Builds a nesting tree of all immutables‍/binders.
void dot(std::ostream &os) const
bool is_recursive() const
const Node * operator[](Def *mut) const
Same as above.
static const Node * lca(const Node *n, const Node *m)
Least common ancestor of n and m.
void dot(std::string s) const
const Node * mut2node(Def *mut) const
const Node * root() const
Vars vars() const
All Vars occurring in this Nest.
const auto & mut2node() const
bool contains(const Def *def) const
bool has_intersection(PooledSet< T > other)
Is ?
This is a thin wrapper for std::span<T, N> with the following additional features:
The World represents the whole program and manages creation of MimIR nodes (Defs).
PooledSet< const Var * > Vars
GIDMap< Def *, To > MutMap