20using Phases = std::deque<std::unique_ptr<Phase>>;
25class Phase :
public fe::RuntimeCast<Phase> {
36 virtual std::unique_ptr<Phase>
recreate();
53 world.DLOG(
"apply phase: `{}`", p_def);
55 if (
auto axm = p_def->isa<
Axm>())
56 if (
auto i = phases.find(axm->flags()); i != phases.end()) {
57 auto phase = i->second(
world);
59 phase->apply(def->isa<
App>());
60 if (phase->redirects())
return phase->take_resolved();
64 fe::throwf(
"phase `{}` not found", axm->sym());
66 fe::throwf(
"unsupported callee for a phase: `{}`", p_def);
69 template<
class A,
class P>
90 bool todo()
const {
return todo_; }
107 template<
class P,
class... Args>
109 P p(std::forward<Args>(
args)...);
165 virtual void reset();
188 const auto&
lattice()
const {
return lattice_; }
192 if (
auto i = lattice_.find(def); i != lattice_.end())
return i->second;
198 auto i = lattice_.find(def);
199 return i != lattice_.end() && i->second == def;
216 if (
auto [i, ins] = lattice_.emplace(concr, abstr); !ins) {
217 if (i->second == abstr)
return false;
220 return touch(),
true;
232 if (
auto [i, ins] = lattice_.emplace(concr, abstr); !ins) {
233 assert((i->second != concr || abstr == concr) &&
"monotonicity violation: must not descend from ⊤");
234 if (i->second == abstr)
return false;
236 }
else if (concr == abstr) {
239 return touch(),
true;
257 void start()
override;
286 std::deque<Def*> worklist_;
289 bool nonlocal_ =
false;
290 bool curr_sparse_ =
false;
292 bool bootstrapping_ =
true;
293 size_t num_drained_ = 0;
333 const Def*
lattice(
const Def* old_def)
const {
return analysis_ ? analysis_->lattice(old_def) :
nullptr; }
338 return l && l != old_def ? l :
nullptr;
372 void start()
override;
376 bool bootstrapping_ =
true;
396 if (
auto subst =
replace(def))
todo =
true, def = subst;
403#define MIM_CONCAT_INNER(a, b) a##b
404#define MIM_CONCAT(a, b) MIM_CONCAT_INNER(a, b)
406#define MIM_REPL(__phases, __annex, ...) MIM_REPL_IMPL(__phases, __annex, __LINE__, __VA_ARGS__)
409#define MIM_REPL_IMPL(__phases, __annex, __id, ...) \
410 struct MIM_CONCAT(Repl_, __id) : ::mim::Repl { \
411 MIM_CONCAT(Repl_, __id)(::mim::World & world, ::mim::flags_t annex) \
412 : Repl(world, annex) {} \
414 const ::mim::Def* replace(const ::mim::Def* def) final __VA_ARGS__ \
416 ::mim::Phase::hook<__annex, MIM_CONCAT(Repl_, __id)>(__phases)
448 const auto&
phases()
const {
return phases_; }
463template<class M =
Def>
483 M*
root()
const {
return root_; }
486 const bool elide_empty_;
487 const bool schedule_;
493template<
class M = Def>
Traverses the current World using Rewriter infrastructure while staying in the same world.
virtual void prepare()
Run before the main analysis.
size_t version() const
Bumped on every observable lattice change; snapshot it around a code region to detect changes.
void start() override
Actual entry.
bool lattice_force(const Def *concr, const Def *abstr)
Non-monotone write of concr ↦ abstr into lattice() and map().
const Def * rewrite_imm_Proxy(const Proxy *proxy) override
By default: ignore Proxys.
Analysis(World &world, std::string name)
void make_dense()
Forces whole-World rounds unconditionally.
bool lattice(const Def *concr, const Def *abstr)
Writes concr ↦ abstr into lattice() and map().
void taint(Def *mut)
Additionally schedules mut for the next sparse round.
virtual void rewrite_annex(flags_t, Sym, const Def *)
const Def * lattice(const Def *def) const
bool is_top(const Def *def) const
virtual void rewrite_external(Def *)
bool is_sparse() const
Does the current round only re-drain last round's dirty mutables?
virtual void reset()
Clears the rewriter map and resets Phase::todo() for the next fixed-point iteration.
virtual void finalize()
Run after the main analysis - only in full rounds, so it always sees the complete abstract World.
const auto & lattice() const
The whole map; used e.g. to diff two fixed-point runs.
bool pin(const Def *def)
Monotonically forces def to ⊤ (keep as is).
bool is_bootstrapping() const
< Disambiguates the Phase/Rewriter double base; for an Analysis both denote the same World.
Analysis(World &world, flags_t annex)
Def * rewrite_mut(Def *) override
Schedules mut for a breadth-first visit of its dependencies and records mut -> mut.
const Def * uncurry_callee() const
Cleanup(World &world, flags_t annex)
void start() override
Actual entry.
ClosedMutPhase(World &world, flags_t annex, bool elide_empty, bool schedule=false)
virtual void visit(M *)=0
ClosedMutPhase(World &world, std::string name, bool elide_empty, bool schedule=false)
World & world() const noexcept
Some "global" variables needed all over the place.
Facility to log what you are doing.
void log(Level level, Loc loc, std::format_string< Args... > fmt, Args &&... args) const
virtual void visit(const Nest &)=0
const Nest & nest() const
NestPhase(World &world, std::string name, bool elide_empty, bool schedule=false)
NestPhase(World &world, flags_t annex, bool elide_empty, bool schedule=false)
Builds a nesting tree for all mutables/binders.
Organizes several Phases into a pipeline.
PhaseMan(World &world, flags_t annex)
void start() final
Actual entry.
const auto & phases() const
void apply(bool, Phases &&)
A Phase performs one self-contained task over the whole World.
virtual std::unique_ptr< Phase > recreate()
Creates a new instance; needed by a fixed-point PhaseMan.
static void hook(Flags2Phases &phases)
void invalidate(bool todo=true)
Signals that another round of fixed-point iteration is required, either as part of.
Phase(World &world, std::string name)
static void run(Args &&... args)
Runs a single Phase.
static std::unique_ptr< Phase > create(const Flags2Phases &phases, const Def *def)
void profile_count(std::string_view key, uint64_t n=1)
Adds n to the custom Profiler counter key of the current run; no-op unless profiling is enabled.
virtual std::unique_ptr< Phase > take_resolved()
The Phase to use instead; nullptr means elide.
virtual void apply(Phase &)
Dito, but invoked by Phase::recreate.
virtual void run()
Entry point and generates some debug output; invokes Phase::start.
std::string_view name() const
virtual void start()=0
Actual entry.
const Vector< std::string > & args()
Command-line arguments passed to this Phase's plugin via -X <plugin>:<arg>.
virtual void apply(const App *)
Invoked if your Phase has additional args.
virtual bool redirects() const
If true, Phase::create uses take_resolved().
virtual bool analyze()
Runs the optional pre-analysis on RWPhase::old_world(), typically to a fixed point,...
World & new_world()
Create new Defs into this.
RWPhase(World &world, flags_t annex, Analysis *analysis=nullptr)
virtual void rewrite_annex(flags_t, Sym, const Def *)
const Def * abstracted(const Def *old_def) const
Returns lattice(old_def) if it differs from old_def (i.e. we learned something), otherwise nullptr.
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
RWPhase(World &world, std::string name, Analysis *analysis=nullptr)
void start() override
Actual entry.
World & world()=delete
Hides both and forbids direct access.
const Analysis * analysis() const
const Def * lattice(const Def *old_def) const
Returns the abstract value computed by the associated Analysis for the given old-world Def,...
World & old_world()
Get old Defs from here.
virtual void rewrite_external(Def *)
const Def * rewrite(const Def *def) final
virtual const Def * replace(const Def *def)=0
Repl(World &world, flags_t annex)
World & world()
replace() inspects and builds Defs of the old world; the RWPhase machinery carries the result over.
virtual const Def * map(const Def *old_def, const Def *new_def)
Rewriter(std::unique_ptr< World > &&ptr)
virtual const Def * rewrite(const Def *)
This is a thin wrapper for absl::InlinedVector<T, N, A> which is a drop-in replacement for std::vecto...
The World represents the whole program and manages creation of MimIR nodes (Defs).
const Driver & driver() const
DefMap< const Def * > Def2Def
auto assert_emplace(C &container, Args &&... args)
Invokes emplace on container, asserts that insertion actually happened, and returns the iterator.
absl::flat_hash_map< flags_t, std::function< std::unique_ptr< Phase >(World &)> > Flags2Phases
Maps an axiom of a Phase to a function that creates one.
std::deque< std::unique_ptr< Phase > > Phases
static consteval flags_t base()