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* inest() const { return inest_; } ///< Immediate nester/parent of this Node.
20 bool is_root() const { return inest_ == 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 struct Children {
33 ///@name Get children as muts and/or nodes.
34 ///@{
35 // clang-format off
36 auto mut2node() const { return mut2node_ | std::views::transform([](auto p) { return std::pair{p.first, const_cast<const Node*>(p.second)}; }); }
37 auto muts() const { return mut2node_ | std::views::keys; }
38 auto nodes() const { return mut2node_ | std::views::transform([](auto p) { return const_cast<const Node*>(p.second); }); }
39 // clang-format on
40 size_t num() const { return mut2node_.size(); } ///< Number of children.
41 ///@}
42
43 /// @name Lookup
44 ///@{
45 const Node* operator[](Def* mut) const { return const_cast<Children*>(this)->operator[](mut); }
46 bool contains(Def* mut) const { return mut2node_.contains(mut); } ///< is @p mut a child?
47 ///@}
48
49 /// @name Iterators
50 ///@{
51 auto begin() const { return mut2node_.cbegin(); }
52 auto end() const { return mut2node_.cend(); }
53 ///@}
54
55 private:
56 const auto& mut2node() { return mut2node_; }
57 auto nodes() { return mut2node_ | std::views::values; }
58 auto muts() { return mut2node_ | std::views::keys; }
59 auto begin() { return mut2node_.begin(); }
60 auto end() { return mut2node_.end(); }
61 Node* operator[](Def* mut) { return mim::lookup(mut2node_, mut); }
62
63 MutMap<Node*> mut2node_;
64
65 friend class Nest;
66 };
67
68 const Children& children() const { return children_; }
69 Children& children() { return children_; }
70 ///@}
71
72 template<bool Forward>
73 struct SiblDeps {
74 /// @name Get sibling dependencies
75 ///@{
76 auto nodes() const {
77 return nodes_ | std::views::transform([](Node* n) { return const_cast<const Node*>(n); });
78 }
79 ///@}
80
81 /// @name Getters
82 ///@{
83 size_t num() const { return nodes().size(); }
84 bool contains(const Node* n) const { return nodes_.contains(n); }
85 ///@}
86
87 /// @name Iterators
88 ///@{
89 auto begin() const { return nodes_.cbegin(); }
90 auto end() const { return nodes_.cend(); }
91 ///@}
92
93 private:
94 const auto& nodes() { return nodes_; }
95 auto begin() { return nodes_.begin(); }
96 auto end() { return nodes_.end(); }
97
98 absl::flat_hash_set<Node*> nodes_;
99
100 friend class Nest;
101 };
102
103 /// @name Sibling Dependencies
104 /// These are the dependencies across children():
105 /// A child `n` depends() on `m`, if a subtree of `n` uses `m`.
106 ///@{
107 template<bool Forward = true>
108 auto& sibl_deps() {
109 nest().calc_sibl_deps();
110 if constexpr (Forward)
111 return sibl_deps_;
112 else
113 return sibl_rev_deps_;
114 }
115
116 template<bool Forward = true>
117 const auto& sibl_deps() const {
118 return const_cast<Node*>(this)->sibl_deps<Forward>();
119 }
120 ///@}
121
122 /// Strongly Connected Component.
123 using SCC = absl::flat_hash_set<const Node*>;
124 /// @name SCCs
125 /// [SCCs](https://en.wikipedia.org/wiki/Strongly_connected_component) for all children dependencies.
126 /// @note The Nest::root() cannot be is_mutually_recursive() by definition.
127 /// If you have a set of mutually recursive Def%s as "root", include them all by using a *virtual root*.
128 ///@{
129 const auto& SCCs() { return sccs().SCCs_; }
130 const auto& topo() const { return sccs().topo_; } ///< Topological sorting of all SCCs.
131 bool is_recursive() const { return sccs().recursive_; }
132 bool is_mutually_recursive() const { return is_recursive() && inest_ && inest_->SCCs_[this]->size() > 1; }
133 bool is_directly_recursive() const { return is_recursive() && (!inest_ || inest_->SCCs_[this]->size() == 1); }
134 ///@}
135
136 private:
137 Node(const Nest& nest, Def* mut, Node* inest)
138 : nest_(nest)
139 , mut_(mut)
140 , inest_(inest)
141 , level_(inest ? inest->level() + 1 : 0) {
142 if (inest) inest->children_.mut2node_.emplace(mut, this);
143 }
144
145 const Node& sccs() const { return nest().calc_SCCs(), *this; }
146
147 void link(Node* other) { this->sibl_deps_.nodes_.emplace(other), other->sibl_rev_deps_.nodes_.emplace(this); }
148 void dot(Tab, std::ostream&) const;
149
150 /// SCCs
151 using Stack = std::stack<Node*>;
152 void calc_SCCs();
153 uint32_t tarjan(uint32_t, Node*, Stack&);
154
155 const Nest& nest_;
156 Def* mut_;
157 Node* inest_;
158 uint32_t level_;
159 uint32_t loop_depth_ : 31 = 0;
160 bool recursive_ : 1 = false;
161 SiblDeps<true> sibl_deps_;
162 SiblDeps<false> sibl_rev_deps_;
163 Children children_;
164 std::deque<std::unique_ptr<SCC>> topo_;
165 absl::node_hash_map<const Node*, const SCC*> SCCs_;
166
167 // implementaiton details
168 static constexpr uint32_t Unvisited = uint32_t(-1);
169 uint32_t idx_ = Unvisited;
170 uint32_t low_ : 31 = 0;
171 bool on_stack_ : 1 = false;
172 Node* curr_child = nullptr;
173
174 friend class Nest;
175 };
176
177 /// @name Constructors
178 ///@{
179 Nest(Def* root);
180 Nest(View<Def*> muts); ///< Constructs a *virtual root* with @p muts as children.
181 Nest(World&); ///< *Virtual root* with all World::externals as children.
182 ///@}
183
184 /// @name Getters
185 ///@{
186 World& world() const { return world_; }
187 const Node* root() const { return root_; }
188 Vars vars() const { return vars_; } ///< All Var%s occurring in this Nest.
189 bool contains(const Def* def) const { return vars().has_intersection(def->free_vars()); }
190 bool is_recursive() const { return calc_SCCs().root()->is_recursive(); }
191 ///@}
192
193 /// @name Nodes
194 ///@{
195 size_t num_nodes() const { return mut2node_.size(); }
196 // clang-format off
197 auto muts() const { return mut2node_ | std::views::keys; }
198 auto nodes() const { return mut2node_ | std::views::transform([](const auto& p) { return (const Node*)p.second.get(); }); }
199 // clang-format on
200 const Node* operator[](Def* mut) const { return const_cast<Nest*>(this)->operator[](mut); }
201 ///@}
202
203 /// @name Iterators
204 ///@{
205 auto begin() const { return mut2node_.cbegin(); }
206 auto end() const { return mut2node_.cend(); }
207 ///@}
208
209 static const Node* lca(const Node* n, const Node* m); ///< Least common ancestor of @p n and @p m.
210
211 /// @name dot
212 /// GraphViz output.
213 ///@{
214 void dot(std::ostream& os) const;
215 void dot(const char* file = nullptr) const;
216 void dot(std::string s) const { dot(s.c_str()); }
217 ///@}
218
219private:
220 auto begin() { return mut2node_.begin(); }
221 auto end() { return mut2node_.end(); }
222
223 void populate();
224 Node* make_node(Def*, Node* inest = nullptr);
225 void calc_sibl_deps(Node*) const;
226 void calc_SCCs(Node*) const;
227
228 Node* operator[](Def* mut) {
229 if (auto i = mut2node_.find(mut); i != mut2node_.end()) return i->second.get();
230 return nullptr;
231 }
232
233 void calc_sibl_deps() const {
234 if (!siblings_) {
235 siblings_ = true;
236 calc_sibl_deps(root_);
237 }
238 }
239
240 const Nest& calc_SCCs() const {
241 if (!sccs_) {
242 sccs_ = true;
243 calc_SCCs(root_);
244 }
245 return *this;
246 }
247
248 World& world_;
249 absl::flat_hash_map<Def*, std::unique_ptr<Node>> mut2node_;
250 Vars vars_;
251 Node* root_;
252 mutable bool siblings_ = false;
253 mutable bool sccs_ = false;
254};
255
256} // namespace mim
Base class for all Defs.
Definition def.h:251
std::string unique_name() const
name + "_" + Def::gid
Definition def.cpp:576
Vars free_vars() const
Compute a global solution by transitively following mutables as well.
Definition def.cpp:334
std::string name() const
Definition nest.h:17
const auto & SCCs()
Definition nest.h:129
auto & sibl_deps()
Definition nest.h:108
const auto & sibl_deps() const
Definition nest.h:117
uint32_t level() const
Definition nest.h:26
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:174
bool is_recursive() const
Definition nest.h:131
const Children & children() const
Definition nest.h:68
bool is_root() const
Definition nest.h:20
absl::flat_hash_set< const Node * > SCC
Strongly Connected Component.
Definition nest.h:123
const auto & topo() const
Topological sorting of all SCCs.
Definition nest.h:130
const Nest & nest() const
Definition nest.h:18
bool is_directly_recursive() const
Definition nest.h:133
bool is_mutually_recursive() const
Definition nest.h:132
Children & children()
Definition nest.h:69
uint32_t loop_depth() const
Definition nest.h:27
const Node * inest() const
Immediate nester/parent of this Node.
Definition nest.h:19
void dot(std::ostream &os) const
Definition dot.cpp:170
bool is_recursive() const
Definition nest.h:190
const Node * operator[](Def *mut) const
Definition nest.h:200
auto nodes() const
Definition nest.h:198
World & world() const
Definition nest.h:186
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:216
auto muts() const
Definition nest.h:197
const Node * root() const
Definition nest.h:187
auto end() const
Definition nest.h:206
Nest(Def *root)
Definition nest.cpp:7
Vars vars() const
All Vars occurring in this Nest.
Definition nest.h:188
auto begin() const
Definition nest.h:205
size_t num_nodes() const
Definition nest.h:195
bool contains(const Def *def) const
Definition nest.h:189
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:37
auto begin() const
Definition nest.h:51
size_t num() const
Number of children.
Definition nest.h:40
bool contains(Def *mut) const
is mut a child?
Definition nest.h:46
friend class Nest
Definition nest.h:65
auto nodes() const
Definition nest.h:38
auto end() const
Definition nest.h:52
auto mut2node() const
Definition nest.h:36
const Node * operator[](Def *mut) const
Definition nest.h:45
auto end() const
Definition nest.h:90
auto begin() const
Definition nest.h:89
auto nodes() const
Definition nest.h:76
friend class Nest
Definition nest.h:100
size_t num() const
Definition nest.h:83
bool contains(const Node *n) const
Definition nest.h:84