7#include <absl/container/btree_map.h>
8#include <absl/container/btree_set.h>
16struct NullSafeDefGIDLt {
17 constexpr bool operator()(
const Def* a,
const Def* b)
const noexcept {
18 return (a ?
a->gid() : 0) < (b ? b->gid() : 0);
38 const Node*
inest()
const {
return inest_; }
42 auto idom()
const {
return calc_dominance()->idom_; }
43 bool is_root()
const {
return inest_ ==
nullptr; }
49 uint32_t
level()
const {
return level_; }
50 uint32_t
loop_depth()
const {
return sccs().loop_depth_; }
53 uint32_t
gid()
const {
return mut_ ? mut_->gid() : 0; }
62 auto mut2node()
const {
return mut2node_ | std::views::transform([](
auto p) {
return std::pair{p.first,
const_cast<const Node*
>(p.second)}; }); }
63 auto muts()
const {
return mut2node_ | std::views::keys; }
64 auto nodes()
const {
return mut2node_ | std::views::transform([](
auto p) {
return const_cast<const Node*
>(p.second); }); }
66 size_t num()
const {
return mut2node_.size(); }
77 auto begin()
const {
return mut2node_.cbegin(); }
78 auto end()
const {
return mut2node_.cend(); }
82 const auto&
mut2node() {
return mut2node_; }
83 auto nodes() {
return mut2node_ | std::views::values; }
84 auto muts() {
return mut2node_ | std::views::keys; }
85 auto begin() {
return mut2node_.begin(); }
86 auto end() {
return mut2node_.end(); }
89 absl::btree_map<Def*, Node*, GIDLt<Def*>> mut2node_;
98 template<
bool Forward>
103 return nodes_ | std::views::transform([](Node* n) {
return const_cast<const Node*
>(n); });
110 bool contains(
const Node* n)
const {
return nodes_.contains(
const_cast<Node*
>(n)); }
115 auto begin()
const {
return nodes_.cbegin(); }
116 auto end()
const {
return nodes_.cend(); }
120 const auto&
nodes() {
return nodes_; }
121 auto begin() {
return nodes_.begin(); }
122 auto end() {
return nodes_.end(); }
124 absl::btree_set<Node*, GIDLt<Node*>> nodes_;
133 template<
bool Forward = true>
135 nest().calc_sibl_deps();
136 if constexpr (Forward)
139 return sibl_rev_deps_;
142 template<
bool Forward = true>
149 using SCC = absl::btree_set<const Node*, GIDLt<const Node*>>;
155 const auto&
SCCs() {
return sccs().SCCs_; }
156 const auto&
topo()
const {
return sccs().topo_; }
171 const Node& sccs()
const {
return nest().calc_SCCs(), *
this; }
173 void link(Node* other) { this->sibl_deps_.nodes_.emplace(other), other->sibl_rev_deps_.nodes_.emplace(
this); }
174 void dot(fe::Tab, std::ostream&)
const;
177 using Stack = std::stack<Node*>;
179 uint32_t tarjan(uint32_t, Node*, Stack&);
182 const Node* calc_dominance()
const;
188 uint32_t loop_depth_ : 31 = 0;
189 bool recursive_ : 1 =
false;
193 std::deque<std::unique_ptr<SCC>> topo_;
194 absl::btree_map<const Node*, const SCC*, GIDLt<const Node*>> SCCs_;
195 mutable const Node* idom_ =
nullptr;
198 mutable std::optional<size_t> postorder_number_ = std::nullopt;
201 static constexpr uint32_t Unvisited = uint32_t(-1);
202 uint32_t idx_ = Unvisited;
203 uint32_t low_ : 31 = 0;
204 bool on_stack_ : 1 =
false;
205 Node* curr_child =
nullptr;
226 bool is_recursive()
const {
return calc_SCCs().root()->is_recursive(); }
233 auto muts()
const {
return mut2node_ | std::views::keys; }
234 auto nodes()
const {
return mut2node_ | std::views::transform([](
const auto& p) {
return (
const Node*)p.second.get(); }); }
238 if (
auto i = mut2node_.find(mut); i != mut2node_.end())
return i->second.get();
245 auto begin()
const {
return mut2node_.cbegin(); }
246 auto end()
const {
return mut2node_.cend(); }
249 template<
bool bootstrapping = false>
255 void dot(std::ostream& os)
const;
256 void dot(
const char* file =
nullptr)
const;
257 void dot(std::string s)
const {
dot(s.c_str()); }
261 auto begin() {
return mut2node_.begin(); }
262 auto end() {
return mut2node_.end(); }
265 Node* make_node(Def*,
Node* inest =
nullptr);
266 void calc_sibl_deps(
Node*)
const;
267 void calc_SCCs(
Node*)
const;
268 void assign_postorder_numbers()
const;
271 void calc_sibl_deps()
const {
274 calc_sibl_deps(root_);
278 const Nest& calc_SCCs()
const {
287 absl::btree_map<Def*, std::unique_ptr<Node>, detail::NullSafeDefGIDLt> mut2node_;
290 mutable bool siblings_ =
false;
291 mutable bool sccs_ =
false;
std::string unique_name() const
name + "_" + Def::gid
Vars free_vars() const
Global set of free Vars: extends local_vars() by transitively following mutables as well.
const auto & sibl_deps() 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 Children & children() const
auto idom() const
Immediate Dominator for children in connected components.
const auto & topo() const
Topological sorting of all SCCs.
const Nest & nest() const
bool is_directly_recursive() const
bool is_mutually_recursive() const
absl::btree_set< const Node *, GIDLt< const Node * > > SCC
Strongly Connected Component.
uint32_t loop_depth() const
const Node * inest() const
Immediate nester/parent of this Node.
uint32_t gid() const
Stable id for deterministic hashing/ordering: the underlying mut's gid, or 0 for the (unique) virtual...
void dot(std::ostream &os) const
bool is_recursive() const
const Node * operator[](Def *mut) const
static const Node * lca(const Node *n, const Node *m)
Least common ancestor of n and m.
Nest & operator=(Nest)=delete
void dot(std::string s) const
const Node * root() const
Vars vars() const
All Vars occurring in this Nest.
Nest(const Nest &)=delete
bool contains(const Def *def) const
bool has_intersection(Set other) const noexcept
Is ?.
The World represents the whole program and manages creation of MimIR nodes (Defs).
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...
Sets< const Var >::Set Vars
size_t num() const
Number of children.
bool contains(Def *mut) const
is mut a child?
const Node * operator[](Def *mut) const
bool contains(const Node *n) const