7#include <absl/container/fixed_array.h>
29 auto ptr = (*ctor)(
world());
59 curr_sparse_ = !dense_ && !nonlocal_ && !dirty_.empty();
67 VLOG(
"sparse round: re-draining {} dirty muts", seeds.size());
73 for (
auto [concr, abstr] : lattice_)
74 if (!concr->isa_mut())
map(concr, abstr);
76 for (
auto mut : seeds)
80 for (
const auto& [flags, e] :
world().annexes())
84 bootstrapping_ =
false;
86 for (
auto mut :
world().externals().muts())
93 profile_count(curr_sparse_ ?
"rounds.sparse" :
"rounds.full");
94 profile_count(
"muts.drained", std::exchange(num_drained_,
size_t(0)));
105 if (
lookup(mut))
return mut;
107 worklist_.emplace_back(mut);
111void Analysis::drain() {
112 while (!worklist_.empty()) {
113 auto mut = worklist_.front();
114 worklist_.pop_front();
118 DLOG(
"enter: {}", mut);
119 for (
auto d : mut->deps())
131 for (uint32_t i = 0;
todo; ++i) {
132 if (i >= max_iters) fe::throwf(
"phase `{}` did not reach a fixed point after {} iterations",
name(), max_iters);
133 VLOG(
"iteration: {}", i);
137 for (
const auto& [flags, e] :
old_world().annexes())
140 bootstrapping_ =
false;
142 for (
auto mut :
old_world().externals().muts())
152 return analysis_->todo();
162 if (old_mut->
is_external()) new_mut->externalize();
171 phases_ = std::move(
phases);
172 name_ += fixed_point_ ?
" tt" :
" ff";
179 for (
auto arg :
args->projs())
186 auto& man =
static_cast<PhaseMan&
>(phase);
188 for (
auto& old_phase : man.phases())
189 new_phases.emplace_back(std::unique_ptr<Phase>(
static_cast<Phase*
>(old_phase->recreate().release())));
190 apply(man.fixed_point(), std::move(new_phases));
198 auto stale = absl::FixedArray<bool>(n,
true);
199 auto ran = absl::FixedArray<bool>(n,
false);
201 auto any_stale = [&stale]() {
return std::ranges::any_of(stale, [](
bool b) {
return b; }); };
203 for (uint32_t iter = 0; any_stale(); ++iter) {
204 if (iter >= max_iters)
205 fe::throwf(
"phase `{}` did not reach a fixed point after {} iterations",
name(), max_iters);
209 for (
size_t i = 0; i != n; ++i) {
210 auto& phase =
phases()[i];
212 VLOG(
"skipping `{}`: World unchanged since its last quiet run", phase->name());
218 auto new_phase = std::unique_ptr<Phase>(
static_cast<Phase*
>(phase->recreate().release()));
219 swap(new_phase, phase);
229 std::ranges::fill(stale,
true);
virtual void prepare()
Run before the main analysis.
void start() override
Actual entry.
virtual void rewrite_annex(flags_t, Sym, const Def *)
virtual void rewrite_external(Def *)
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.
Def * rewrite_mut(Def *) override
Schedules mut for a breadth-first visit of its dependencies and records mut -> mut.
static auto uncurry_args(const Def *def)
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
bool is_external() const noexcept
const Vector< std::string > & args(Sym plugin) const
Yields an empty Vector if plugin has none.
auto phase(flags_t flags)
static T as(const Def *def)
PhaseMan(World &world, flags_t annex)
void start() final
Actual entry.
void apply(bool, Phases &&)
virtual std::unique_ptr< Phase > recreate()
Creates a new instance; needed by a fixed-point PhaseMan.
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 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 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>.
void stop()
Marks the end of the most recently started Phase run.
void start(std::string_view name)
void count(std::string_view key, uint64_t n=1)
Adds n to counter key of the currently running Span; no-op if no Span is running or n is 0.
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.
virtual void rewrite_annex(flags_t, Sym, const Def *)
void start() override
Actual entry.
World & old_world()
Get old Defs from here.
virtual void rewrite_external(Def *)
friend void swap(Rewriter &rw1, Rewriter &rw2) noexcept
virtual const Def * map(const Def *old_def, const Def *new_def)
std::deque< Def2Def > old2news_
virtual const Def * rewrite(const Def *)
auto enter(Def *new_mut)
Updates curr_mut() to new_mut and restores it at the end of the scope.
virtual const Def * lookup(const Def *old_def)
Lookup old_def by searching in reverse through the stack of maps.
This is a thin wrapper for absl::InlinedVector<T, N, A> which is a drop-in replacement for std::vecto...
const Def * attach(flags_t, Sym, const Def *)
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.
#define DLOG(...)
Vaporizes to nothingness in Debug build.
std::deque< std::unique_ptr< Phase > > Phases
static constexpr plugin_t flags2plugin(flags_t f)
static Sym demangle(Driver &, plugin_t plugin)
Reverts an Axm::mangled string to a Sym.