16using Passes = std::deque<std::unique_ptr<Pass>>;
26class Stage :
public fe::RuntimeCast<Stage> {
36 virtual std::unique_ptr<Stage>
recreate();
53 world.DLOG(
"apply stage: `{}`", p_def);
55 if (
auto axm = p_def->isa<
Axm>())
56 if (
auto i = stages.find(axm->flags()); i != stages.end()) {
57 auto stage = i->second(
world);
59 stage->apply(def->isa<
App>());
60 if (stage->redirects())
return stage->take_resolved();
64 error(
"stage `{}` not found", axm->sym());
66 error(
"unsupported callee for a stage: `{}`", p_def);
69 template<
class A,
class P>
112 size_t index()
const {
return index_; }
171 virtual void*
alloc() {
return nullptr; }
172 virtual void*
copy(
const void*) {
return nullptr; }
195 bool inspect() const final { fe::unreachable(); }
199 bool empty()
const {
return passes_.empty(); }
200 const auto&
passes()
const {
return passes_; }
210 if (
auto i = registry_.find(key); i != registry_.end())
return i->second;
216 if (
auto pass =
find(std::type_index(
typeid(P))))
return static_cast<P*
>(pass);
220 void add(std::unique_ptr<Pass>&& pass) {
221 fixed_point_ |= pass->fixed_point();
223 auto type_idx = std::type_index(
typeid(*p));
224 if (
auto pass =
find(type_idx))
error(
"already added `{}`", pass->name());
225 registry_.emplace(type_idx, p);
226 passes_.emplace_back(std::move(pass));
235 State(
const State&) =
delete;
236 State(State&&) =
delete;
237 State& operator=(State) =
delete;
243 std::stack<Def*> stack;
244 MutMap<undo_t> mut2visit;
251 void pop_states(
undo_t undo);
252 State& curr_state() {
253 assert(!states_.empty());
254 return states_.back();
256 const State& curr_state()
const {
257 assert(!states_.empty());
258 return states_.back();
260 undo_t curr_undo()
const {
return states_.size() - 1; }
265 const Def* rewrite(
const Def*);
267 const Def* map(
const Def* old_def,
const Def* new_def) {
268 curr_state().old2new[old_def] = new_def;
269 curr_state().old2new.emplace(new_def, new_def);
273 std::optional<const Def*> lookup(
const Def* old_def) {
274 for (
auto& state : states_ | std::views::reverse)
275 if (
auto i = state.old2new.find(old_def); i != state.old2new.end())
return i->second;
282 undo_t analyze(
const Def*);
283 bool analyzed(
const Def* def) {
284 for (
auto& state : states_ | std::views::reverse)
285 if (state.analyzed.contains(def))
return true;
286 curr_state().analyzed.emplace(def);
292 absl::flat_hash_map<std::type_index, Pass*> registry_;
293 std::deque<State> states_;
294 Def* curr_mut_ =
nullptr;
295 bool fixed_point_ =
false;
298 template<
class P,
class M>
305template<
class P,
class M = Def>
314 if constexpr (std::is_same<M, Def>::value)
321 if constexpr (std::is_same<M, Def>::value)
330template<
class P,
class M = Def>
349 assert(!
states().empty());
354 return std::get<I>(
data());
362 template<
size_t I,
class K>
374 const auto& mut2visit =
Super::man().curr_state().mut2visit;
375 if (
auto i = mut2visit.find(mut); i != mut2visit.end())
return i->second;
381 for (
auto i =
states().size(); i-- != 0;)
390 void*
alloc()
override {
return new typename P::Data(); }
391 void*
copy(
const void* p)
override {
return new typename P::Data(*
static_cast<const typename P::Data*
>(p)); }
392 void dealloc(
void* state)
override {
delete static_cast<typename P::Data*
>(state); }
const Def * uncurry_callee() const
World & world() const noexcept
Some "global" variables needed all over the place.
void dealloc(void *state) override
Destructor.
undo_t undo_visit(Def *mut) const
Retrieves the point to backtrack to just before mut was seen the very first time.
FPPass(World &world, flags_t annex)
auto & data(const K &key)
Use this for your convenience if P::Data is a map.
FPPass(World &world, std::string name)
void * copy(const void *p) override
Copy constructor.
undo_t curr_undo() const
Current undo point.
const auto & states() const
bool fixed_point() const override
std::tuple<> Data
Default.
void * alloc() override
Default constructor.
auto & data(const K &key)
Use this for your convenience if P::Data<I> is a map.
undo_t undo_enter(Def *mut) const
Retrieves the point to backtrack to just before rewriting mut's body.
Facility to log what you are doing.
void log(Level level, Loc loc, std::format_string< Args... > fmt, Args &&... args) const
An optimizer that combines several optimizations in an optimal way.
void init(PassMan *) final
Pass * find(std::type_index key)
void apply(Stage &stage) final
Dito, but invoked by Stage::recreate.
bool inspect() const final
Should the PassMan even consider this pass?
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
All Passes that want to be registered in the PassMan must implement this interface.
virtual void enter()
Invoked just before Pass::rewriteing PassMan::curr_mut's body.
const Proxy * proxy(const Def *type, Defs ops, u32 tag=0)
virtual undo_t analyze(const Proxy *)
const PassMan & man() const
virtual void * alloc()
Default constructor.
virtual const Def * rewrite(const Var *var)
virtual void dealloc(void *)
Destructor.
virtual const Def * rewrite(const Proxy *proxy)
virtual undo_t analyze(const Var *)
Pass(World &world, std::string name)
virtual void init(PassMan *)
virtual undo_t analyze(const Def *)
virtual void prepare()
Invoked once before entering the main rewrite loop.
virtual void * copy(const void *)
Copy constructor.
virtual bool fixed_point() const
Pass(World &world, flags_t annex)
virtual bool inspect() const =0
Should the PassMan even consider this pass?
virtual const Def * rewrite(const Def *def)
const Proxy * isa_proxy(const Def *def, u32 tag=0)
Check whether given def is a Proxy whose Proxy::pass matches this Pass's IPass::index.
const Proxy * as_proxy(const Def *def, u32 tag=0)
RWPass(World &world, std::string name)
bool inspect() const override
Should the PassMan even consider this pass?
RWPass(World &world, flags_t annex)
Common base for Phase and Pass.
virtual std::unique_ptr< Stage > recreate()
Creates a new instance; needed by a fixed-point PhaseMan.
virtual std::unique_ptr< Stage > take_resolved()
The Stage to use instead; nullptr means elide.
virtual bool redirects() const
If true, Stage::create uses take_resolved().
virtual void apply(const App *)
Invoked if your Stage has additional args.
std::string_view name() const
static void hook(Flags2Stages &stages)
virtual void apply(Stage &)
Dito, but invoked by Stage::recreate.
Stage(World &world, std::string name)
static std::unique_ptr< Stage > create(const Flags2Stages &stages, const Def *def)
A variable introduced by a binder (mutable).
The World represents the whole program and manages creation of MimIR nodes (Defs).
const Driver & driver() const
const Proxy * proxy(const Def *type, Defs ops, u32 index, u32 tag)
DefMap< const Def * > Def2Def
Vector< const Def * > DefVec
auto assert_emplace(C &container, Args &&... args)
Invokes emplace on container, asserts that insertion actually happened, and returns the iterator.
std::deque< std::unique_ptr< Pass > > Passes
absl::flat_hash_map< flags_t, std::function< std::unique_ptr< Stage >(World &)> > Flags2Stages
Maps an an axiom of a Stage to a function that creates one.
GIDSet< const Def * > DefSet
void error(std::format_string< Args... > fmt, Args &&... args)
Wraps std::format to throw T with a formatted message.
static constexpr undo_t No_Undo
static consteval flags_t base()