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 <optional>
5#include <ranges>
6
7#include "mim/def.h"
8
9namespace mim {
10
11/// Builds a nesting tree of all *mutables*/binders.
12class Nest {
13public:
14 class Node {
15 public:
16 /// @name Getters
17 ///@{
18 std::string name() const { return mut() ? mut()->unique_name() : std::string("<virtual>"); }
19 const Nest& nest() const { return nest_; }
20 const Node* inest() const { return inest_; } ///< Immediate nester/parent of this Node.
21 /// [Immediate Dominator](https://en.wikipedia.org/wiki/Dominator_(graph_theory)) for children in connected components.
22 /// This is used to transform first order programs into structured form in the [sflow](mim::plug::sflow)
23 /// plugin and for late code placement in [Nest::lca].
24 auto idom() const { return calc_dominance()->idom_; }
25 bool is_root() const { return inest_ == nullptr; }
26 /// The *mutable* capsulated in this Node or `nullptr`, if it's a *virtual root* comprising several Node%s.
27 Def* mut() const {
28 assert(mut_ || is_root());
29 return mut_;
30 }
31 uint32_t level() const { return level_; }
32 uint32_t loop_depth() const { return sccs().loop_depth_; }
33 ///@}
34
35 /// @name Children
36 ///@{
37 struct Children {
38 ///@name Get children as muts and/or nodes.
39 ///@{
40 // clang-format off
41 auto mut2node() const { return mut2node_ | std::views::transform([](auto p) { return std::pair{p.first, const_cast<const Node*>(p.second)}; }); }
42 auto muts() const { return mut2node_ | std::views::keys; }
43 auto nodes() const { return mut2node_ | std::views::transform([](auto p) { return const_cast<const Node*>(p.second); }); }
44 // clang-format on
45 size_t num() const { return mut2node_.size(); } ///< Number of children.
46 ///@}
47
48 /// @name Lookup
49 ///@{
50 const Node* operator[](Def* mut) const { return const_cast<Children*>(this)->operator[](mut); }
51 bool contains(Def* mut) const { return mut2node_.contains(mut); } ///< is @p mut a child?
52 ///@}
53
54 /// @name Iterators
55 ///@{
56 auto begin() const { return mut2node_.cbegin(); }
57 auto end() const { return mut2node_.cend(); }
58 ///@}
59
60 private:
61 const auto& mut2node() { return mut2node_; }
62 auto nodes() { return mut2node_ | std::views::values; }
63 auto muts() { return mut2node_ | std::views::keys; }
64 auto begin() { return mut2node_.begin(); }
65 auto end() { return mut2node_.end(); }
66 Node* operator[](Def* mut) { return mim::lookup(mut2node_, mut); }
67
68 MutMap<Node*> mut2node_;
69
70 friend class Nest;
71 };
72
73 const Children& children() const { return children_; }
74 Children& children() { return children_; }
75 ///@}
76
77 template<bool Forward>
78 struct SiblDeps {
79 /// @name Get sibling dependencies
80 ///@{
81 auto nodes() const {
82 return nodes_ | std::views::transform([](Node* n) { return const_cast<const Node*>(n); });
83 }
84 ///@}
85
86 /// @name Getters
87 ///@{
88 size_t num() const { return nodes().size(); }
89 bool contains(const Node* n) const { return nodes_.contains(n); }
90 ///@}
91
92 /// @name Iterators
93 ///@{
94 auto begin() const { return nodes_.cbegin(); }
95 auto end() const { return nodes_.cend(); }
96 ///@}
97
98 private:
99 const auto& nodes() { return nodes_; }
100 auto begin() { return nodes_.begin(); }
101 auto end() { return nodes_.end(); }
102
103 absl::flat_hash_set<Node*> nodes_;
104
105 friend class Nest;
106 };
107
108 /// @name Sibling Dependencies
109 /// These are the dependencies across children():
110 /// A child `n` depends() on `m`, if a subtree of `n` uses `m`.
111 ///@{
112 template<bool Forward = true>
113 auto& sibl_deps() {
114 nest().calc_sibl_deps();
115 if constexpr (Forward)
116 return sibl_deps_;
117 else
118 return sibl_rev_deps_;
119 }
120
121 template<bool Forward = true>
122 const auto& sibl_deps() const {
123 return const_cast<Node*>(this)->sibl_deps<Forward>();
124 }
125 ///@}
126
127 /// Strongly Connected Component.
128 using SCC = absl::flat_hash_set<const Node*>;
129 /// @name SCCs
130 /// [SCCs](https://en.wikipedia.org/wiki/Strongly_connected_component) for all children dependencies.
131 /// @note The Nest::root() cannot be is_mutually_recursive() by definition.
132 /// If you have a set of mutually recursive Def%s as "root", include them all by using a *virtual root*.
133 ///@{
134 const auto& SCCs() { return sccs().SCCs_; }
135 const auto& topo() const { return sccs().topo_; } ///< Topological sorting of all SCCs.
136 bool is_recursive() const { return sccs().recursive_; }
137 bool is_mutually_recursive() const { return is_recursive() && inest_ && inest_->SCCs_[this]->size() > 1; }
138 bool is_directly_recursive() const { return is_recursive() && (!inest_ || inest_->SCCs_[this]->size() == 1); }
139 ///@}
140
141 private:
142 Node(const Nest& nest, Def* mut, Node* inest)
143 : nest_(nest)
144 , mut_(mut)
145 , inest_(inest)
146 , level_(inest ? inest->level() + 1 : 0) {
147 if (inest) inest->children_.mut2node_.emplace(mut, this);
148 }
149
150 const Node& sccs() const { return nest().calc_SCCs(), *this; }
151
152 void link(Node* other) { this->sibl_deps_.nodes_.emplace(other), other->sibl_rev_deps_.nodes_.emplace(this); }
153 void dot(Tab, std::ostream&) const;
154
155 /// SCCs
156 using Stack = std::stack<Node*>;
157 void calc_SCCs();
158 uint32_t tarjan(uint32_t, Node*, Stack&);
159
160 /// Dominance
161 const Node* calc_dominance() const;
162
163 const Nest& nest_;
164 Def* mut_;
165 Node* inest_;
166 uint32_t level_;
167 uint32_t loop_depth_ : 31 = 0;
168 bool recursive_ : 1 = false;
169 SiblDeps<true> sibl_deps_;
170 SiblDeps<false> sibl_rev_deps_;
171 Children children_;
172 std::deque<std::unique_ptr<SCC>> topo_;
173 absl::flat_hash_map<const Node*, const SCC*> SCCs_;
174 mutable const Node* idom_ = nullptr;
175 // Nodes higher up in dominator tree within same sibling layer have higher postorder numbers.
176 // This property is used to efficiently find the correct node for late code placement via [Nest::lca].
177 mutable std::optional<size_t> postorder_number_ = std::nullopt;
178
179 // implementaiton details
180 static constexpr uint32_t Unvisited = uint32_t(-1);
181 uint32_t idx_ = Unvisited;
182 uint32_t low_ : 31 = 0;
183 bool on_stack_ : 1 = false;
184 Node* curr_child = nullptr;
185
186 friend class Nest;
187 };
188
189 /// @name Constructors
190 ///@{
191 Nest(Def* root);
192 Nest(View<Def*> muts); ///< Constructs a *virtual root* with @p muts as children.
193 Nest(World&); ///< *Virtual root* with all World::externals as children.
194 Nest(const Nest&) = delete;
195 Nest(Nest&&) = delete;
196 Nest& operator=(Nest) = delete;
197 ///@}
198
199 /// @name Getters
200 ///@{
201 World& world() const { return world_; }
202 const Node* root() const { return root_; }
203 Vars vars() const { return vars_; } ///< All Var%s occurring in this Nest.
204 bool contains(const Def* def) const { return vars().has_intersection(def->free_vars()); }
205 bool is_recursive() const { return calc_SCCs().root()->is_recursive(); }
206 ///@}
207
208 /// @name Nodes
209 ///@{
210 size_t num_nodes() const { return mut2node_.size(); }
211 // clang-format off
212 auto muts() const { return mut2node_ | std::views::keys; }
213 auto nodes() const { return mut2node_ | std::views::transform([](const auto& p) { return (const Node*)p.second.get(); }); }
214 // clang-format on
215 const Node* operator[](Def* mut) const { return const_cast<Nest*>(this)->operator[](mut); }
216 ///@}
217
218 /// @name Iterators
219 ///@{
220 auto begin() const { return mut2node_.cbegin(); }
221 auto end() const { return mut2node_.cend(); }
222 ///@}
223
224 template<bool bootstrapping = false>
225 static const Node* lca(const Node* n, const Node* m); ///< Least common ancestor of @p n and @p m.
226
227 /// @name dot
228 /// GraphViz output.
229 ///@{
230 void dot(std::ostream& os) const;
231 void dot(const char* file = nullptr) const;
232 void dot(std::string s) const { dot(s.c_str()); }
233 ///@}
234
235private:
236 auto begin() { return mut2node_.begin(); }
237 auto end() { return mut2node_.end(); }
238
239 void populate();
240 Node* make_node(Def*, Node* inest = nullptr);
241 void calc_sibl_deps(Node*) const;
242 void calc_SCCs(Node*) const;
243 void assign_postorder_numbers() const;
244
245 Node* operator[](Def* mut) {
246 if (auto i = mut2node_.find(mut); i != mut2node_.end()) return i->second.get();
247 return nullptr;
248 }
249
250 void calc_sibl_deps() const {
251 if (!siblings_) {
252 siblings_ = true;
253 calc_sibl_deps(root_);
254 }
255 }
256
257 const Nest& calc_SCCs() const {
258 if (!sccs_) {
259 sccs_ = true;
260 calc_SCCs(root_);
261 }
262 return *this;
263 }
264
265 World& world_;
266 absl::flat_hash_map<Def*, std::unique_ptr<Node>> mut2node_;
267 Vars vars_;
268 Node* root_;
269 mutable bool siblings_ = false;
270 mutable bool sccs_ = false;
271};
272
273} // namespace mim
Base class for all Defs.
Definition def.h:251
std::string unique_name() const
name + "_" + Def::gid
Definition def.cpp:578
Vars free_vars() const
Compute a global solution by transitively following mutables as well.
Definition def.cpp:336
std::string name() const
Definition nest.h:18
const auto & SCCs()
Definition nest.h:134
auto & sibl_deps()
Definition nest.h:113
const auto & sibl_deps() const
Definition nest.h:122
uint32_t level() const
Definition nest.h:31
Def * mut() const
The mutable capsulated in this Node or nullptr, if it's a virtual root comprising several Nodes.
Definition nest.h:27
friend class Nest
Definition nest.h:186
bool is_recursive() const
Definition nest.h:136
const Children & children() const
Definition nest.h:73
bool is_root() const
Definition nest.h:25
auto idom() const
Immediate Dominator for children in connected components.
Definition nest.h:24
absl::flat_hash_set< const Node * > SCC
Strongly Connected Component.
Definition nest.h:128
const auto & topo() const
Topological sorting of all SCCs.
Definition nest.h:135
const Nest & nest() const
Definition nest.h:19
bool is_directly_recursive() const
Definition nest.h:138
bool is_mutually_recursive() const
Definition nest.h:137
Children & children()
Definition nest.h:74
uint32_t loop_depth() const
Definition nest.h:32
const Node * inest() const
Immediate nester/parent of this Node.
Definition nest.h:20
Nest(Nest &&)=delete
void dot(std::ostream &os) const
Definition dot.cpp:170
bool is_recursive() const
Definition nest.h:205
const Node * operator[](Def *mut) const
Definition nest.h:215
auto nodes() const
Definition nest.h:213
World & world() const
Definition nest.h:201
static const Node * lca(const Node *n, const Node *m)
Least common ancestor of n and m.
Definition nest.cpp:105
Nest & operator=(Nest)=delete
void dot(std::string s) const
Definition nest.h:232
auto muts() const
Definition nest.h:212
const Node * root() const
Definition nest.h:202
auto end() const
Definition nest.h:221
Nest(Def *root)
Definition nest.cpp:7
Vars vars() const
All Vars occurring in this Nest.
Definition nest.h:203
auto begin() const
Definition nest.h:220
Nest(const Nest &)=delete
size_t num_nodes() const
Definition nest.h:210
bool contains(const Def *def) const
Definition nest.h:204
bool has_intersection(Set other) const noexcept
Is ?.
Definition sets.h:271
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:31
Definition ast.h:14
auto lookup(const C &container, const K &key)
Yields pointer to element (or the element itself if it is already a pointer), if found and nullptr ot...
Definition util.h:100
Span< const T, N > View
Definition span.h:98
Sets< const Var >::Set Vars
Definition def.h:97
Node
Definition def.h:112
GIDMap< Def *, To > MutMap
Definition def.h:84
auto muts() const
Definition nest.h:42
auto begin() const
Definition nest.h:56
size_t num() const
Number of children.
Definition nest.h:45
bool contains(Def *mut) const
is mut a child?
Definition nest.h:51
friend class Nest
Definition nest.h:70
auto nodes() const
Definition nest.h:43
auto end() const
Definition nest.h:57
auto mut2node() const
Definition nest.h:41
const Node * operator[](Def *mut) const
Definition nest.h:50
auto end() const
Definition nest.h:95
auto begin() const
Definition nest.h:94
auto nodes() const
Definition nest.h:81
friend class Nest
Definition nest.h:105
size_t num() const
Definition nest.h:88
bool contains(const Node *n) const
Definition nest.h:89