MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
nest.h
Go to the documentation of this file.
1#pragma once
2
3#include <memory>
4#include <ranges>
5
6#include "mim/def.h"
7
8namespace mim {
9
10/// Builds a nesting tree of all *immutables*/binders.
11class Nest {
12public:
13 class Node {
14 public:
15 /// @name Getters
16 ///@{
17 std::string name() const { return mut() ? mut()->unique_name() : std::string("<virtual>"); }
18 const Nest& nest() const { return nest_; }
19 const Node* parent() const { return parent_; }
20 bool is_root() const { return parent_ == nullptr; }
21 /// The mutable capsulated in this Node or `nullptr`, if it's a *virtual root* comprising several Node%s.
22 Def* mut() const {
23 assert(mut_ || is_root());
24 return mut_;
25 }
26 uint32_t level() const { return level_; }
27 uint32_t loop_depth() const { return sccs().loop_depth_; }
28 ///@}
29
30 /// @name Children
31 ///@{
32 auto child_muts() const { return child_mut2node_ | std::views::keys; }
33 auto child_nodes() const {
34 return child_mut2node_
35 | std::views::transform([](const auto& pair) { return const_cast<const Node*>(pair.second); });
36 }
37 auto child_mut2node() const {
38 return child_mut2node_ | std::views::transform([](const auto& pair) {
39 return std::pair{pair.first, const_cast<const Node*>(pair.second)};
40 });
41 }
42 const Node* child(Def* mut) const {
43 if (auto i = child_mut2node_.find(mut); i != child_mut2node_.end()) return i->second;
44 return nullptr;
45 }
46 size_t num_children() const { return child_mut2node_.size(); }
47 ///@}
48
49 /// @name depends/controls
50 /// These are the dependencies across children():
51 /// * A child `n` depends() on `m`, if a subtree of `n` uses `m`.
52 /// * Conversly: `m` controls() `n`.
53 ///@{
54 auto depends() const {
55 return deps().depends_ | std::views::transform([](Node* n) { return const_cast<const Node*>(n); });
56 }
57 auto controls() const {
58 return deps().controls_ | std::views::transform([](Node* n) { return const_cast<const Node*>(n); });
59 }
60 size_t num_depends() const { return depends().size(); }
61 ///@}
62
63 /// Strongly Connected Component.
64 using SCC = absl::flat_hash_set<const Node*>;
65 /// @name SCCs
66 /// [SCCs](https://en.wikipedia.org/wiki/Strongly_connected_component) for all children dependencies.
67 /// @note The Nest::root() cannot be is_mutually_recursive() by definition.
68 /// If you have a set of mutually recursive Def%s as "root", include them all by using a *virtual root*.
69 ///@{
70 const auto& SCCs() { return sccs().SCCs_; }
71 const auto& topo() const { return sccs().topo_; } ///< Topological sorting of all SCCs.
72 bool is_recursive() const { return sccs().recursive_; }
73 bool is_mutually_recursive() const { return is_recursive() && parent_ && parent_->SCCs_[this]->size() > 1; }
74 bool is_directly_recursive() const { return is_recursive() && (!parent_ || parent_->SCCs_[this]->size() == 1); }
75 ///@}
76
77 private:
78 Node(const Nest& nest, Def* mut, Node* parent)
79 : nest_(nest)
80 , mut_(mut)
81 , parent_(parent)
82 , level_(parent ? parent->level() + 1 : 0) {
83 if (parent) parent->child_mut2node_.emplace(mut, this);
84 }
85
86 const Node& deps() const { return nest().deps(), *this; }
87 const Node& sccs() const { return nest().sccs(), *this; }
88
89 void link(Node* node) { this->depends_.emplace(node), node->controls_.emplace(this); }
90 void dot(Tab, std::ostream&) const;
91
92 /// SCCs
93 using Stack = std::stack<Node*>;
94 void find_SCCs();
95 uint32_t tarjan(uint32_t, Node*, Stack&);
96
97 const Nest& nest_;
98 Def* mut_;
99 Node* parent_;
100 uint32_t level_;
101 uint32_t loop_depth_ : 31 = 0;
102 bool recursive_ : 1 = false;
103 MutMap<Node*> child_mut2node_;
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_;
108
109 // implementaiton details
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;
115
116 friend class Nest;
117 };
118
119 /// @name Constructors
120 ///@{
121 Nest(Def* root);
122 Nest(View<Def*> muts); ///< Constructs a *virtual root* with @p muts as children.
123 Nest(World&); ///< *Virtual root* with all World::externals as children.
124 ///@}
125
126 /// @name Getters
127 ///@{
128 World& world() const { return world_; }
129 const Node* root() const { return root_; }
130 Vars vars() const { return vars_; } ///< All Var%s occurring in this Nest.
131 bool contains(const Def* def) const { return vars().has_intersection(def->free_vars()); }
132 bool is_recursive() const { return sccs().root()->is_recursive(); }
133 ///@}
134
135 /// @name Nodes
136 ///@{
137 auto muts() const { return mut2node_ | std::views::keys; }
138 auto nodes() const {
139 return mut2node_ | std::views::transform([](const auto& pair) { return (const Node*)pair.second.get(); });
140 }
141 const auto& mut2node() const { return mut2node_; }
142 size_t num_nodes() const { return mut2node_.size(); }
143 const Node* mut2node(Def* mut) const { return mut2node_nonconst(mut); }
144 const Node* operator[](Def* mut) const { return mut2node(mut); } ///< Same as above.
145 ///@}
146
147 static const Node* lca(const Node* n, const Node* m); ///< Least common ancestor of @p n and @p m.
148
149 /// @name dot
150 /// GraphViz output.
151 ///@{
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()); }
155 ///@}
156
157private:
158 Node* mut2node_nonconst(Def* mut) const {
159 if (auto i = mut2node_.find(mut); i != mut2node_.end()) return i->second.get();
160 return nullptr;
161 }
162
163 void populate();
164 Node* make_node(Def*, Node* parent = nullptr);
165 void deps(Node*) const;
166 void find_SCCs(Node*) const;
167
168 const Nest& deps() const {
169 if (!deps_) {
170 deps_ = true;
171 deps(root_);
172 }
173 return *this;
174 }
175
176 const Nest& sccs() const {
177 if (!sccs_) {
178 sccs_ = true;
179 find_SCCs(root_);
180 }
181 return *this;
182 }
183
184 World& world_;
185 absl::flat_hash_map<Def*, std::unique_ptr<Node>> mut2node_;
186 Vars vars_;
187 Node* root_;
188 mutable bool deps_ = false;
189 mutable bool sccs_ = false;
190};
191
192} // namespace mim
Base class for all Defs.
Definition def.h:212
std::string unique_name() const
name + "_" + Def::gid
Definition def.cpp:480
Vars free_vars() const
Compute a global solution, i.e., by transitively following mutables as well.
Definition def.cpp:304
std::string name() const
Definition nest.h:17
size_t num_depends() const
Definition nest.h:60
const auto & SCCs()
Definition nest.h:70
auto child_mut2node() const
Definition nest.h:37
auto child_muts() const
Definition nest.h:32
const Node * child(Def *mut) const
Definition nest.h:42
size_t num_children() const
Definition nest.h:46
uint32_t level() const
Definition nest.h:26
auto controls() const
Definition nest.h:57
Def * mut() const
The mutable capsulated in this Node or nullptr, if it's a virtual root comprising several Nodes.
Definition nest.h:22
friend class Nest
Definition nest.h:116
bool is_recursive() const
Definition nest.h:72
auto child_nodes() const
Definition nest.h:33
auto depends() const
Definition nest.h:54
bool is_root() const
Definition nest.h:20
const Node * parent() const
Definition nest.h:19
absl::flat_hash_set< const Node * > SCC
Strongly Connected Component.
Definition nest.h:64
const auto & topo() const
Topological sorting of all SCCs.
Definition nest.h:71
const Nest & nest() const
Definition nest.h:18
bool is_directly_recursive() const
Definition nest.h:74
bool is_mutually_recursive() const
Definition nest.h:73
uint32_t loop_depth() const
Definition nest.h:27
Builds a nesting tree of all immutables‍/binders.
Definition nest.h:11
void dot(std::ostream &os) const
Definition dot.cpp:168
bool is_recursive() const
Definition nest.h:132
const Node * operator[](Def *mut) const
Same as above.
Definition nest.h:144
auto nodes() const
Definition nest.h:138
World & world() const
Definition nest.h:128
static const Node * lca(const Node *n, const Node *m)
Least common ancestor of n and m.
Definition nest.cpp:78
void dot(std::string s) const
Definition nest.h:154
auto muts() const
Definition nest.h:137
const Node * mut2node(Def *mut) const
Definition nest.h:143
const Node * root() const
Definition nest.h:129
Nest(Def *root)
Definition nest.cpp:11
Vars vars() const
All Vars occurring in this Nest.
Definition nest.h:130
const auto & mut2node() const
Definition nest.h:141
size_t num_nodes() const
Definition nest.h:142
bool contains(const Def *def) const
Definition nest.h:131
bool has_intersection(PooledSet< T > other)
Is ?
Definition pool.h:72
This is a thin wrapper for std::span<T, N> with the following additional features:
Definition span.h:28
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:33
Definition ast.h:14
PooledSet< const Var * > Vars
Definition def.h:80
GIDMap< Def *, To > MutMap
Definition def.h:68