Thorin 1.9.0
The Higher ORder INtermediate representation
Loading...
Searching...
No Matches
phase.h
Go to the documentation of this file.
1#pragma once
2
3#include "thorin/def.h"
4#include "thorin/rewrite.h"
5
7#include "thorin/pass/pass.h"
8
9namespace thorin {
10
11class World;
12
13/// As opposed to a Pass, a Phase does one thing at a time and does not mix with other Phase%s.
14/// They are supposed to classically run one after another.
15/// Phase::dirty indicates whether we may need a Cleanup afterwards.
16class Phase {
17public:
18 Phase(World& world, std::string_view name, bool dirty)
19 : world_(world)
20 , name_(name)
21 , dirty_(dirty) {}
22 virtual ~Phase() = default;
23
24 /// @name Getters
25 ///@{
26 World& world() { return world_; }
27 std::string_view name() const { return name_; }
28 bool is_dirty() const { return dirty_; }
29 ///@}
30
31 /// @name run
32 ///@{
33 virtual void run(); ///< Entry point and generates some debug output; invokes Phase::start.
34
35 /// Runs a single Phase.
36 template<class P, class... Args> static void run(Args&&... args) {
37 P p(std::forward<Args>(args)...);
38 p.run();
39 }
40 ///@}
41
42protected:
43 virtual void start() = 0; ///< Actual entry.
44
46 std::string name_;
47 bool dirty_;
48};
49
50/// Visits the current Phase::world and constructs a new RWPhase::world along the way.
51/// It recursively **rewrites** all World::externals().
52/// @note You can override Rewriter::rewrite, Rewriter::rewrite_imm, and Rewriter::rewrite_mut.
53class RWPhase : public Phase, public Rewriter {
54public:
55 RWPhase(World& world, std::string_view name)
56 : Phase(world, name, true)
57 , Rewriter(world) {}
58
59 World& world() { return Phase::world(); }
60 void start() override;
61};
62
63/// Removes unreachable and dead code by rebuilding the whole World into a new one and `swap`ping afterwards.
64class Cleanup : public Phase {
65public:
67 : Phase(world, "cleanup", false) {}
68
69 void start() override;
70};
71
72/// Like a RWPhase but starts with a fixed-point loop of FPPhase::analyze beforehand.
73/// Inherit from this one to implement a classic data-flow analysis.
74class FPPhase : public RWPhase {
75public:
76 FPPhase(World& world, std::string_view name)
77 : RWPhase(world, name) {}
78
79 void start() override;
80 virtual bool analyze() = 0;
81};
82
83/// Wraps a Pass as a Phase.
84template<class P> class PassPhase : public Phase {
85public:
86 template<class... Args>
87 PassPhase(World& world, Args&&... args)
88 : Phase(world, {}, false)
89 , man_(world) {
90 man_.template add<P>(std::forward<Args>(args)...);
91 name_ = std::string(man_.passes().back()->name()) + ".pass_phase";
92 }
93
94 void start() override { man_.run(); }
95
96private:
97 PassMan man_;
98};
99
100/// Wraps a PassMan pipeline as a Phase.
101class PassManPhase : public Phase {
102public:
103 PassManPhase(World& world, std::unique_ptr<PassMan>&& man)
104 : Phase(world, "pass_man_phase", false)
105 , man_(std::move(man)) {}
106
107 void start() override { man_->run(); }
108
109private:
110 std::unique_ptr<PassMan> man_;
111};
112
113/// Organizes several Phase%s as a pipeline.
114class Pipeline : public Phase {
115public:
117 : Phase(world, "pipeline", true) {}
118
119 void start() override;
120
121 /// @name phases
122 ///@{
123 const auto& phases() const { return phases_; }
124
125 /// Add a Phase.
126 /// You don't need to pass the World to @p args - it will be passed automatically.
127 /// If @p P is a Pass, this method will wrap this in a PassPhase.
128 template<class P, class... Args> auto add(Args&&... args) {
129 if constexpr (std::is_base_of_v<Pass, P>) {
130 return add<PassPhase<P>>(std::forward<Args>(args)...);
131 } else {
132 auto p = std::make_unique<P>(world(), std::forward<Args&&>(args)...);
133 auto phase = p.get();
134 phases_.emplace_back(std::move(p));
135 if (phase->is_dirty()) phases_.emplace_back(std::make_unique<Cleanup>(world()));
136 return phase;
137 }
138 }
139 ///@}
140
141private:
142 std::deque<std::unique_ptr<Phase>> phases_;
143};
144
145/// Transitively visits all *reachable* Scope%s in World that do not have free variables.
146/// We call these Scope%s *top-level* Scope%s.
147/// Select with `elide_empty` whether you want to visit trivial Scope%s of *muts* without body.
148/// Assumes that you don't change anything - hence `dirty` flag is set to `false`.
149/// @deprecated Use ClosedMutPhase instead.
150class ScopePhase : public Phase {
151public:
152 ScopePhase(World& world, std::string_view name, bool elide_empty)
153 : Phase(world, name, false)
154 , elide_empty_(elide_empty) {}
155
156 void start() override;
157 virtual void visit(const Scope&) = 0;
158
159protected:
160 const Scope& scope() const { return *scope_; }
161
162private:
163 bool elide_empty_;
164 const Scope* scope_ = nullptr;
165};
166
167/// Transitively visits all *reachable* closed mutables (Def::is_closed()) in World.
168/// Select with `elide_empty` whether you want to visit trivial *muts* without body.
169/// Assumes that you don't change anything - hence `dirty` flag is set to `false`.
170/// If you a are only interested in specific mutables, you can pass this to @p M.
171template<class M = Def> class ClosedMutPhase : public Phase {
172public:
173 ClosedMutPhase(World& world, std::string_view name, bool elide_empty)
174 : Phase(world, name, false)
175 , elide_empty_(elide_empty) {}
176
177 void start() override {
179 for (const auto& [_, mut] : world().externals()) queue.push(mut);
180
181 while (!queue.empty()) {
182 auto mut = queue.pop();
183 if (auto m = mut->isa<M>(); m && m->is_closed() && (!elide_empty_ || m->is_set())) visit(curr_mut_ = m);
184
185 for (auto op : mut->extended_ops())
186 for (auto mut : op->local_muts()) queue.push(mut);
187 }
188 }
189
190protected:
191 virtual void visit(M*) = 0;
192 M* curr_mut() const { return curr_mut_; }
193
194private:
195 bool elide_empty_;
196 M* curr_mut_;
197};
198
199} // namespace thorin
Removes unreachable and dead code by rebuilding the whole World into a new one and swapping afterward...
Definition phase.h:64
Cleanup(World &world)
Definition phase.h:66
void start() override
Actual entry.
Definition phase.cpp:28
Transitively visits all reachable closed mutables (Def::is_closed()) in World.
Definition phase.h:171
M * curr_mut() const
Definition phase.h:192
void start() override
Actual entry.
Definition phase.h:177
ClosedMutPhase(World &world, std::string_view name, bool elide_empty)
Definition phase.h:173
virtual void visit(M *)=0
Muts local_muts() const
Definition def.cpp:327
Like a RWPhase but starts with a fixed-point loop of FPPhase::analyze beforehand.
Definition phase.h:74
FPPhase(World &world, std::string_view name)
Definition phase.h:76
void start() override
Actual entry.
Definition phase.cpp:19
virtual bool analyze()=0
Wraps a PassMan pipeline as a Phase.
Definition phase.h:101
void start() override
Actual entry.
Definition phase.h:107
PassManPhase(World &world, std::unique_ptr< PassMan > &&man)
Definition phase.h:103
An optimizer that combines several optimizations in an optimal way.
Definition pass.h:107
const auto & passes() const
Definition pass.h:115
void run()
Run all registered passes on the whole World.
Definition pass.cpp:41
Wraps a Pass as a Phase.
Definition phase.h:84
PassPhase(World &world, Args &&... args)
Definition phase.h:87
void start() override
Actual entry.
Definition phase.h:94
As opposed to a Pass, a Phase does one thing at a time and does not mix with other Phases.
Definition phase.h:16
std::string name_
Definition phase.h:46
virtual void start()=0
Actual entry.
virtual ~Phase()=default
World & world_
Definition phase.h:45
World & world()
Definition phase.h:26
Phase(World &world, std::string_view name, bool dirty)
Definition phase.h:18
bool is_dirty() const
Definition phase.h:28
virtual void run()
Entry point and generates some debug output; invokes Phase::start.
Definition phase.cpp:7
static void run(Args &&... args)
Runs a single Phase.
Definition phase.h:36
bool dirty_
Definition phase.h:47
std::string_view name() const
Definition phase.h:27
Organizes several Phases as a pipeline.
Definition phase.h:114
const auto & phases() const
Definition phase.h:123
auto add(Args &&... args)
Add a Phase.
Definition phase.h:128
void start() override
Actual entry.
Definition phase.cpp:41
Pipeline(World &world)
Definition phase.h:116
Visits the current Phase::world and constructs a new RWPhase::world along the way.
Definition phase.h:53
RWPhase(World &world, std::string_view name)
Definition phase.h:55
void start() override
Actual entry.
Definition phase.cpp:13
World & world()
Definition phase.h:59
Recurseivly rewrites part of a program into the provided World.
Definition rewrite.h:9
Transitively visits all reachable Scopes in World that do not have free variables.
Definition phase.h:150
void start() override
Actual entry.
Definition phase.cpp:45
ScopePhase(World &world, std::string_view name, bool elide_empty)
Definition phase.h:152
virtual void visit(const Scope &)=0
const Scope & scope() const
Definition phase.h:160
A Scope represents a region of Defs that are live from the view of an entry's Var.
Definition scope.h:22
The World represents the whole program and manages creation of Thorin nodes (Defs).
Definition world.h:35
const auto & externals() const
Definition world.h:150
bool empty() const
Definition util.h:150
bool push(T val)
Definition util.h:142
#define M(S, D)
Definition span.h:103
Definition cfg.h:11