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