5#include <absl/container/fixed_array.h>
25 auto ptr = (*ctor)(
world());
46 for (
auto arg : app->args())
48 passes.emplace_back(std::unique_ptr<Pass>(
static_cast<Pass*
>(stage.release())));
53void PassMan::push_state() {
55 states_.emplace_back(
passes().size());
58 auto&& prev_state = states_[states_.size() - 2];
59 curr_state().curr_mut = prev_state.stack.top();
60 curr_state().stack = prev_state.stack;
61 curr_state().mut2visit = prev_state.mut2visit;
64 for (
size_t i = 0; i !=
passes().size(); ++i)
65 curr_state().data[i] = passes_[i]->copy(prev_state.data[i]);
69void PassMan::pop_states(
size_t undo) {
70 while (states_.size() != undo) {
71 for (
size_t i = 0, e = curr_state().data.size(); i != e; ++i)
72 passes_[i]->dealloc(curr_state().data[i]);
75 curr_state().curr_mut->set(curr_state().old_ops);
83 for (
auto&& pass : passes_)
84 ILOG(
" 🔹 `{}`", pass->name());
87 auto num =
passes().size();
88 states_.emplace_back(num);
89 for (
size_t i = 0; i != num; ++i) {
90 auto pass = passes_[i].get();
93 curr_state().data[i] = pass->alloc();
96 for (
auto&& pass : passes_)
99 for (
auto mut :
world().copy_externals()) {
101 if (mut->is_set()) curr_state().stack.push(mut);
104 while (!curr_state().stack.empty()) {
106 curr_mut_ =
pop(curr_state().stack);
107 VLOG(
"⚙️ state {}: `{}`", states_.size() - 1, curr_mut_);
109 if (!curr_mut_->is_set())
continue;
111 for (
auto&& pass : passes_)
112 if (pass->inspect()) pass->enter();
114 DLOG(
"curr_mut: {} : {}", curr_mut_, curr_mut_->type());
116 auto new_defs = absl::FixedArray<const Def*>(curr_mut_->num_ops());
117 for (
size_t i = 0, e = curr_mut_->num_ops(); i != e; ++i)
118 new_defs[i] = rewrite(curr_mut_->op(i));
119 curr_mut_->set(new_defs);
124 for (
auto op : curr_mut_->
deps())
125 undo = std::min(undo, analyze(op));
128 assert(!proxy_ &&
"proxies must not occur anymore after leaving a mut with No_Undo");
129 DLOG(
"=== done ===");
132 DLOG(
"=== undo: {} -> {} ===", undo, curr_state().stack.top());
144const Def* PassMan::rewrite(
const Def* old_def) {
145 if (!old_def->
has_dep())
return old_def;
147 if (
auto mut = old_def->
isa_mut()) {
148 curr_state().mut2visit.emplace(mut, curr_undo());
149 return map(mut, mut);
152 if (
auto new_def = lookup(old_def)) {
153 if (old_def == *new_def)
156 return map(old_def, rewrite(*new_def));
159 auto new_type = old_def->
type() ? rewrite(old_def->
type()) : nullptr;
160 auto new_ops = absl::FixedArray<const Def*>(old_def->
num_ops());
161 for (
size_t i = 0, e = old_def->
num_ops(); i != e; ++i)
162 new_ops[i] = rewrite(old_def->
op(i));
163 auto new_def = old_def->
rebuild(new_type, new_ops);
166 if (
auto&& pass = passes_[
proxy->pass()]; pass->inspect()) {
167 if (
auto rw = pass->rewrite(
proxy); rw !=
proxy)
return map(old_def, rewrite(rw));
170 for (
auto&& pass : passes_) {
171 if (!pass->inspect())
continue;
173 if (
auto var = new_def->isa<
Var>()) {
174 if (
auto rw = pass->rewrite(var); rw != var)
return map(old_def, rewrite(rw));
176 if (
auto rw = pass->rewrite(new_def); rw != new_def)
return map(old_def, rewrite(rw));
181 return map(old_def, new_def);
187 if (!def->has_dep() || analyzed(def)) {
189 }
else if (
auto mut = def->isa_mut()) {
190 if (mut->is_set()) curr_state().stack.push(mut);
193 undo = passes_[
proxy->pass()]->analyze(
proxy);
195 auto var = def->isa<
Var>();
197 for (
auto op : def->deps())
198 undo = std::min(undo, analyze(op));
200 for (
auto&& pass : passes_)
201 if (pass->inspect()) undo = std::min(undo, var ? pass->analyze(var) : pass->analyze(def));
Defs deps() const noexcept
constexpr auto ops() const noexcept
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
const Def * op(size_t i) const noexcept
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
const Def * rebuild(World &w, const Def *type, Defs ops) const
Def::rebuilds this Def while using new_op as substitute for its i'th Def::op.
constexpr size_t num_ops() const noexcept
auto stage(flags_t flags)
void run()
Run all registered passes on the whole World.
void add(std::unique_ptr< Pass > &&pass)
PassMan(World &world, flags_t annex)
const auto & passes() const
const Proxy * proxy(const Def *type, Defs ops, u32 tag=0)
Pass(World &world, std::string name)
virtual void init(PassMan *)
virtual void run()
Entry point and generates some debug output; invokes Phase::start.
virtual std::unique_ptr< Stage > recreate()
Creates a new instance; needed by a fixed-point PhaseMan.
static auto create(const Flags2Stages &stages, const Def *def)
Stage(World &world, std::string name)
The World represents the whole program and manages creation of MimIR nodes (Defs).
World & verify()
Verifies that all externals() and annexes() are Def::is_closed(), if MIM_ENABLE_CHECKS.
void debug_dump()
Dump in Debug build if World::log::level is Log::Level::Debug.
#define DLOG(...)
Vaporizes to nothingness in Debug build.
auto pop(S &s) -> decltype(s.top(), typename S::value_type())
std::deque< std::unique_ptr< Pass > > Passes
static constexpr undo_t No_Undo