18bool ADCE::Analysis::is_dead(
const Def* var)
const {
23const Def* ADCE::Analysis::rewrite_imm_App(
const App* app) {
24 auto abstr_arg =
rewrite(app->arg());
25 auto abstr_callee =
rewrite(app->callee());
28 auto n = lam->num_tvars();
29 auto abstr_vars =
DefVec(n, [&](
size_t i) ->
const Def* {
30 auto var = lam->tvar(i);
31 if (lam->is_dependent())
return pin(var), var;
34 return lattice(var, dead), dead;
37 if (n > 1)
lattice(lam->var(),
world().tuple(abstr_vars));
46 for (
auto def :
world().externals().muts())
50void ADCE::Analysis::analyze(
const Def* def) {
52 if (def->isa<Var>())
return;
53 if (
auto [_, ins] = visited_.emplace(def); !ins)
return;
56 if (
auto dead = def->isa<Proxy>()) {
57 if (dead->tag() ==
Proxy_Dead && pin(dead->op(0)))
log().d(
"live: {}", dead->op(0));
61 if (
auto app = def->isa<App>()) {
65 auto n = lam->num_tvars();
66 for (
size_t i = 0; i != n; ++i)
67 if (!is_dead(lam->tvar(i)))
analyze(app->arg(n, i));
69 for (
auto d : lam->deps())
73 }
else if (
auto [lam, var] = def->isa_binder<Lam>(); lam && lam->is_rewritable()) {
74 log().d(
"unknown lam: {}", lam);
75 for (
auto v : lam->tvars())
79 for (
auto d : def->deps())
87Sieve ADCE::sieve(Lam* lam) {
88 if (
auto s = fe::lookup(lam2sieve_, lam))
return *
s;
90 auto n = lam->num_tvars();
91 auto keep = !lam->is_rewritable() || !lam->has_var()
93 : Sieve(lam->tvars(), [this](const Def* var) {
return !analysis_.is_dead(var); });
94 return lam2sieve_.emplace(lam, std::move(keep)).first->second;
97Lam* ADCE::build_lam(Lam* old_lam) {
98 if (
auto new_lam = fe::lookup(lam_old2new_, old_lam))
return new_lam;
101 auto keep = sieve(old_lam);
102 auto n = keep.num_old();
103 auto new_doms =
rewrite(keep.gather(old_lam->doms(n)));
105 log().d(
"{} → {}: {} of {} vars dead", old_lam, new_lam, n - keep.num_new(), n);
107 lam_old2new_[old_lam] = new_lam;
108 lam_new2old_[new_lam] = old_lam;
110 auto old_vars = old_lam->tvars();
111 auto new_vars =
DefVec(n, [&](
size_t i) ->
const Def* {
112 if (
auto j = keep[i]; j !=
Sieve::Gone)
return new_lam->var(keep.num_new(), j)->set(old_vars[i]->
dbg());
116 map(old_lam->var(), new_vars);
117 auto _ =
enter(old_lam);
118 new_lam->set(
rewrite(old_lam->filter()),
rewrite(old_lam->body()));
129 if (
auto keep = sieve(old_lam); !keep.all()) {
130 auto new_lam = build_lam(old_lam);
138 if (!sieve(old_lam).all())
return build_lam(old_lam);
const Def * rewrite_imm_App(const App *) final
const Def * rewrite_mut_Lam(Lam *) final
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.
auto targs(Projector auto f) const noexcept
const Def * callee() const
Def * set(size_t i, const Def *)
Successively set from left to right.
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Lam * set(Filter filter, const Def *body)
static Lam * isa_rewritable(const Def *def)
Yields def as a mutable Lam, if it is_rewritable() and nullptr otherwise.
void invalidate(bool todo=true)
Signals that another round of fixed-point iteration is required, either as part of.
const fe::Log & log() const
void profile_count(std::string_view key, uint64_t n=1)
Adds n to the custom fe::Profiler counter key of the current run; no-op unless profiling is enabled.
static const Proxy * isa(const Def *def)
virtual bool analyze()
Runs the optional pre-analysis on old_world(), typically to a fixed point, before rewriting begins.
World & new_world()
Create new Defs into this.
const Def * lookup(const Def *) override
Lookup old_def by searching in reverse through the stack of maps.
const Def * lattice(const Def *old_def) const
Returns the abstract value computed by the associated Analysis for the given old-world Def,...
const Def * rewrite_imm_App(const App *) override
const Def * map(const Def *old_def, const Def *new_def)
virtual const Def * rewrite_mut_Lam(Lam *)
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.
static constexpr size_t Gone
const Def * app(const Def *callee, const Def *arg)
const Def * bot(const Def *type)
const Proxy * proxy(const Def *type, Defs ops, u32 tag, bool vars=false, bool muts=false)
const Def * raw_app(const Axm *axm, u8 curry, u8 trip, const Def *type, const Def *callee, const Def *arg)
Lam * mut_lam(const Pi *pi)
fe::Vector< const Def * > DefVec