14 if (
auto pi =
Pi::isa_cn(def); pi && pi->isa_imm())
return pi;
22bool Scalarize::Analysis::kept(
const Pi* pi,
size_t dom)
const {
24 if (!abstr)
return false;
28 if (
auto mask =
Lit::isa<u64>(abstr))
return (*mask >> dom) & 1;
32void Scalarize::Analysis::keep(
const Pi* pi,
size_t dom) {
35 if (dom >= pi->num_tdoms())
return;
44 auto next = mask | (
u64(1) << dom);
45 if (next == mask)
return;
46 lattice_force(pi,
world().lit_nat(next));
47 DLOG(
"keep: {} #{}", pi, dom);
53 if (!set.emplace(def).second)
return;
55 for (
auto d : def->
deps())
59void Scalarize::Analysis::pin_tree(
const Def* def) {
61 pin_tree(def, visited);
64void Scalarize::Analysis::pin_tree(
const Def* def,
DefSet& visited) {
65 if (!visited.emplace(def).second)
return;
67 for (
auto d : def->deps())
71void Scalarize::Analysis::inspect(
const Def* def) {
78 if (
auto app = def->isa<
App>()) {
85 if (app->uncurry_callee()->isa<
Axm>()) {
88 for (
auto d = def;
auto a =
d->isa<
App>();
d =
a->callee())
90 pin_tree(app->callee_type()->dom(), skips);
91 pin_tree(app->type(), skips);
97 if (
auto lam = app->arg()->isa_mut<
Lam>()) pin_tree(lam->type());
104 if (
auto pi = app->callee_type(); pi->isa_imm() && pi->dom() != app->arg()->type()) {
106 pin_tree(app->arg()->type());
110 if (def->isa<
Var>())
return;
115 if (
auto tuple = def->isa<
Tuple>(); tuple && tuple->type()->isa_mut())
116 for (
auto op : tuple->ops())
117 pin_tree(
op->type());
126 visited.emplace(lam->type());
127 for (
auto d : lam->type()->deps())
128 pin_tree(d, visited);
133 for (
auto inner = lam->body()->isa_mut<
Lam>(); inner;) {
134 pin_tree(inner->type(), visited);
135 inner = inner->is_set() ? inner->body()->isa_mut<
Lam>() : nullptr;
141 for (
size_t i = 0, e = def->num_ops(); i != e; ++i) {
142 auto op = def->op(i);
143 auto lam =
op ?
op->isa_mut<
Lam>() : nullptr;
145 if (
auto pi =
isa_flattenable(lam->type()); pi && !(def->isa<
App>() && i == 0)) pin(pi);
149 const Def* idx_tuple =
nullptr;
150 const Def*
idx =
nullptr;
151 if (
auto ex = def->isa<
Extract>())
152 idx_tuple = ex->tuple(),
idx = ex->index();
153 else if (
auto in = def->isa<
Insert>())
154 idx_tuple = in->tuple(),
idx = in->index();
155 if (!idx_tuple ||
Lit::isa(idx))
return;
157 if (
auto var = idx_tuple->isa<
Var>()) {
159 }
else if (
auto proj = idx_tuple->isa<
Extract>()) {
160 if (
auto var = proj->tuple()->isa<
Var>()) {
162 if (
auto i =
Lit::isa(proj->index()))
171const Def* Scalarize::Analysis::rewrite(
const Def* old) {
180Vector<bool> Scalarize::Analysis::plan(
const Def* type)
const {
183 auto n = pi->num_tdoms();
185 mask.assign(n,
false);
186 for (
size_t i = 0; i != n; ++i) {
190 auto t = pi->tdom(i);
191 if (!kept(pi, i) &&
t->isa_imm() &&
t->num_tprojs() > 1) mask[i] =
any =
true;
193 if (!any) mask.clear();
204 if (mask.empty())
return RWPhase::rewrite_imm_Pi(pi);
208 for (
size_t i = 0, n = pi->num_tdoms(); i != n; ++i) {
211 auto pieces = t->tprojs();
212 doms.insert(doms.end(), pieces.begin(), pieces.end());
214 doms.emplace_back(t);
220 DLOG(
"scalarize {} ~> {}", pi, sca);
227 if (mask.empty())
return RWPhase::rewrite_mut_Lam(old);
233 auto pi = RWPhase::rewrite_imm_Pi(old->
type())->as<
Pi>();
239 DLOG(
"scalarize {} : {} ~> {} : {}", old, old->
type(), sca, sca->
type());
246 for (
size_t i = 0, v = 0; i != n; ++i) {
249 auto pieces =
DefVec(t->num_tprojs(), [&](
size_t) { return sca->var(v++); });
250 params.emplace_back(w.tuple(t, pieces));
252 params.emplace_back(sca->var(v++));
255 map(old->
var(), w.tuple(params));
263 for (
size_t i = 0, n = app->num_targs(); i != n; ++i) {
264 auto arg =
rewrite(app->targ(i));
265 if (i < mask.size() && mask[i]) {
266 auto pieces = arg->tprojs();
267 args.insert(
args.end(), pieces.begin(), pieces.end());
269 args.emplace_back(arg);
280 if (
auto mask = analysis_.plan(app->
callee_type()); !mask.empty())
284 return RWPhase::rewrite_imm_App(app);
const auto & lattice() const
The whole map; used e.g. to diff two fixed-point runs.
const Pi * callee_type() const
const Def * callee() const
Defs deps() const noexcept
const Def * tvar(nat_t i) noexcept
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
const Def * var(nat_t a, nat_t i) noexcept
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
nat_t num_tvars() noexcept
const Def * filter() const
static std::optional< T > isa(const Def *def)
static T as(const Def *def)
void invalidate(bool todo=true)
Signals that another round of fixed-point iteration is required, either as part of.
const Vector< std::string > & args()
Command-line arguments passed to this Phase's plugin via -X <plugin>:<arg>.
A dependent function type.
static const Pi * isa_cn(const Def *d)
Is this a continuation - i.e. is the Pi::codom mim::Bottom?
const Def * codom() const
World & new_world()
Create new Defs into this.
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
World & world()=delete
Hides both and forbids direct access.
const Def * lattice(const Def *old_def) const
Returns the abstract value computed by the associated Analysis for the given old-world Def,...
virtual const Def * rewrite_stub(Def *, Def *)
virtual const Def * map(const Def *old_def, const Def *new_def)
virtual const Def * rewrite(const Def *)
const Def * rewrite_imm_Pi(const Pi *) final
const Def * rewrite_imm_App(const App *) final
const Def * rewrite_mut_Lam(Lam *) final
This is a thin wrapper for absl::InlinedVector<T, N, A> which is a drop-in replacement for std::vecto...
const Def * app(const Def *callee, const Def *arg)
#define DLOG(...)
Vaporizes to nothingness in Debug build.
Vector< const Def * > DefVec
static void collect(DefSet &set, const Def *def)
Collects def's immutable subtree into set; stops at mutables.
Lam * isa_optimizable(Lam *lam)
These are Lams that are.
static const Pi * isa_flattenable(const Def *def)
The only Pis we ever reshape: immutable (non-dependent) continuations.
GIDSet< const Def * > DefSet
static constexpr auto BitmaskWidth
Number of params a single u64 keep-bitmask can represent; wider doms fall back to the ⊤ sentinel.
Vector(I, I, A=A()) -> Vector< typename std::iterator_traits< I >::value_type, Default_Inlined_Size< typename std::iterator_traits< I >::value_type >, A >