11 if (
auto pi =
Pi::isa_cn(def); pi && pi->isa_imm())
return pi;
18 return std::ranges::none_of(sigma->ops(), [](
const Def* op) { return op->isa<Type>(); });
25 for (
const Def* d = app;
auto a = d->isa<
App>(); d = a->callee())
29 for (; pi && --n != 0;)
31 if (!pi)
return false;
34 if (
auto ex = dom->isa<
Extract>()) dom = ex->tuple();
35 return dom->isa<
Var>();
42bool Scalarize::Analysis::kept(
const Pi* pi,
size_t dom)
const {
43 if (
is_top(pi))
return true;
44 auto mask = fe::lookup(keeps_, pi);
45 return mask && mask->test(dom);
48void Scalarize::Analysis::keep(
const Pi* pi,
size_t dom) {
49 if (dom >= pi->num_tdoms() ||
is_top(pi))
return;
50 auto& mask = keeps_[pi];
51 if (mask.test(dom))
return;
53 log().d(
"keep {}#{}", pi, dom);
57void Scalarize::Analysis::keep_var(
const Def* def) {
68void Scalarize::Analysis::pin_opaque(
DefSet& structural,
const Def* type) {
69 if (transparent(type)) {
70 if (structural.emplace(type).second)
71 for (
auto op :
type->ops())
72 pin_opaque(structural, op);
78void Scalarize::Analysis::keep_indexed(
const Def* tuple,
const Def* idx) {
89const Def* Scalarize::Analysis::rewrite_mut_Lam(Lam* lam) {
91 if (!lam->is_rewritable()) {
92 auto structural =
DefSet();
93 pin_opaque(structural, lam->type());
100const Def* Scalarize::Analysis::rewrite_imm_App(
const App* app) {
107const Def* Scalarize::Analysis::rewrite_imm_Extract(
const Extract* ex) {
109 keep_indexed(ex->tuple(), ex->index());
113const Def* Scalarize::Analysis::rewrite_imm_Insert(
const Insert* ins) {
115 keep_indexed(ins->tuple(), ins->index());
119fe::Bitset Scalarize::Analysis::plan(
const Def* type)
const {
120 auto mask = fe::Bitset();
123 if (
auto sig = pi->dom()->isa_mut<Sigma>(); sig && sig->has_var())
return mask;
124 for (
size_t i = 0, n = pi->num_tdoms(); i != n; ++i) {
125 auto t = pi->tdom(i);
126 if (!kept(pi, i) && (
t->isa_imm() ||
is_value_telescope(t)) &&
t->num_tprojs() > 1) mask.set(i);
136const Def* Scalarize::Keep::rewrite(
const Def* old_def) {
137 if (!has_cn(old_def) && !
has_intersection(old_def))
return sca_.rewrite(old_def);
142bool Scalarize::Keep::has_cn(
const Def* def) {
143 if (
auto [i, ins] = has_cn_.emplace(def,
false); !ins)
return i->second;
145 for (
auto d : def->deps())
147 return has_cn_[def] = res;
160 auto keep = Keep(*
this);
161 auto callee = keep.rewrite(app->
callee());
165const Def* Scalarize::flatten(
Rewriter& rw,
const Pi* pi,
const fe::Bitset& mask) {
171 auto num = size_t(0);
173 for (
size_t i = 0; i != n; ++i) {
174 num += mask[i] ? ts[i]->num_tprojs() : 1;
175 deps |= mask[i] && ts[i]->isa_binder<Sigma>().second;
181 auto sigma =
w.mut_sigma(num);
182 for (
size_t i = 0, v = 0; i != n; ++i) {
184 sigma->set(v++, ts[i]);
187 auto k = ts[i]->num_tprojs();
189 for (
size_t j = 0; j != k; ++j, ++v) {
190 sigma->set(v,
w.component(ts[i], parts, k, j));
191 parts.emplace_back(sigma->var(num, v));
197 for (
size_t i = 0; i != n; ++i) {
199 auto pieces = ts[i]->tprojs();
200 doms.insert(doms.end(), pieces.begin(), pieces.end());
202 doms.emplace_back(ts[i]);
209 log().d(
"scalarize {} → {}", pi, sca);
214Lam* Scalarize::stub(Lam* old,
const fe::Bitset& mask) {
215 auto n = old->num_tvars();
218 auto keep = Keep(*
this);
219 auto& rw = old->is_rewritable() ?
static_cast<Rewriter&
>(*this) : keep;
220 auto type = mask.any() ? flatten(rw, old->type()->as<Pi>(), mask) : rw.
rewrite(old->
type());
222 for (
size_t i = 0; i != n; ++i)
223 if (mask[i]) types[i] = rw.
rewrite(old->tvar(i)->type());
226 auto sca =
w.mut_lam(
type->as<Pi>())->set(old->dbg_key());
228 if (!old->is_set() || mask.none())
return sca;
233 for (
size_t i = 0, v = 0; i != n; ++i) {
236 auto pieces =
DefVec(
t->num_tprojs(), [&](
size_t) { return sca->var(num_sca, v++); });
237 params.emplace_back(
w.tuple(t, pieces));
239 params.emplace_back(sca->var(num_sca, v++));
242 map(old->var(),
w.tuple(params));
247 auto mask = analysis_.plan(old->
type());
bool is_top(const Def *def) const
const Def * rewrite_mut_Lam(Lam *mut) override
static const Def * uncurry_callee(const Def *def)
The innermost App::callee - the one that isn't an App itself.
const Def * callee() const
std::pair< D *, const Var * > isa_binder() const
Is this a mutable that introduces a Var?
nat_t num_vars() noexcept
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
static std::optional< T > isa(const Def *def)
void invalidate(bool todo=true)
Signals that another round of fixed-point iteration is required, either as part of.
const fe::Log & log() const
A dependent function type.
const Def * tdom(nat_t i) const noexcept
static const Pi * isa_cn(const Def *d)
const Def * codom() const
nat_t num_tdoms() const noexcept
World & new_world()
Create new Defs into this.
const Def * coerce(const Def *new_type, const Def *new_val)
Converts the new new_val into a value of the new new_type, where a checking position demands it.
bool is_top(const Def *old_def) const
const Def * rewrite_stub(Def *, Def *) override
const Def * rewrite_imm_App(const App *) override
Recurseivly rebuilds part of a program into the provided World w.r.t. Rewriter::map.
bool has_intersection(const Def *old_def)
Does old_def depend on the old Vars of any scope?
void bind_old(const Var *var)
Adds the old var - if any - to the innermost scope.
virtual const Def * rewrite_imm_Extract(const Extract *)
virtual const Def * rewrite_imm_Insert(const Insert *)
const Def * map(const Def *old_def, const Def *new_def)
virtual const Def * rewrite_mut_Lam(Lam *)
virtual const Def * rewrite_imm_Pi(const Pi *)
virtual const Def * rewrite(const Def *)
virtual const Def * rewrite_imm_App(const App *)
const Def * rewrite_imm_Pi(const Pi *) final
const Def * rewrite_imm_App(const App *) final
const Def * rewrite_mut_Lam(Lam *) final
A variable introduced by a binder (mutable).
static std::pair< const Var *, std::optional< nat_t > > isa_tproj(const Def *def)
Matches a Var v itself or an Extract v#j of it.
const Def * app(const Def *callee, const Def *arg)
static const Pi * isa_flattenable(const Def *def)
The only Pis we ever reshape: immutable (non-dependent) continuations.
static bool is_value_telescope(const Def *def)
A dependent Sigma of values only; other mutable Sigmas may be recursive or pack an existential,...
fe::Vector< const Def * > DefVec
GIDSet< const Def * > DefSet
static bool is_polymorphic_arg(const App *app)
Is the argument of the Axm application app typed by one of the Axm's type variables?