MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
clos.h
Go to the documentation of this file.
1#pragma once
2
3#include <mim/world.h>
4
5#include <mim/plug/mem/mem.h>
6
8
9namespace mim::plug::clos {
10
11/// @name Closures
12///@{
13
14/// Lightweight, non-owning view onto a closure literal `(env_type, fn, env)`; see isa_clos_lit.
15class ClosLit {
16public:
17 /// @name Getters
18 ///@{
19 const Sigma* type() const { return def_->type()->isa<Sigma>(); }
20
21 const Def* env() const;
22 const Def* env_type() const { return env()->type(); }
23
24 const Def* fnc() const;
25 const Pi* fnc_type() const { return fnc()->type()->isa<Pi>(); }
26 Lam* fnc_as_lam() const;
27
28 const Def* env_var() const;
29 const Def* ret_var() const { return fnc_as_lam()->ret_var(); }
30 ///@}
31
32 /// @name Predicates
33 ///@{
34 explicit operator bool() const { return def_ != nullptr; }
35 operator const Tuple*() const { return def_; }
36 const Tuple* operator->() const { return def_; }
37
38 bool is_returning() const { return Pi::isa_returning(fnc_type()); }
39 bool is_basicblock() const { return Pi::isa_basicblock(fnc_type()); }
40 ///@}
41
42private:
43 explicit ClosLit(const Tuple* def)
44 : def_(def) {}
45
46 const Tuple* def_;
47
48 friend ClosLit isa_clos_lit(const Def*, bool);
49};
50
51/// Tries to match a closure literal.
52/// If @p fn_isa_lam, additionally requires the code part to be a Lam.
53ClosLit isa_clos_lit(const Def* def, bool fn_isa_lam = true);
54
55/// Pack a typed closure.
56/// This assumes that @p fn expects the environment at its env_param()%th argument.
57const Def* clos_pack(const Def* env, const Def* fn, const Def* ct = nullptr);
58
59/// Deconstruct a closure into `(env_type, function, env)`.
60/// **Important**: use this or ClosLit to destruct closures, since typechecking dependent pairs is currently
61/// broken.
62std::tuple<const Def*, const Def*, const Def*> clos_unpack(const Def* c);
63
64/// Apply a closure to arguments.
65const Def* clos_apply(const Def* closure, const Def* args);
66inline const Def* apply_closure(const Def* closure, Defs args) {
67 return clos_apply(closure, closure->world().tuple(args));
68}
69
70/// If @p def is a projection `var#i` of the Var of some mutable of type @p N, returns `(projection, binder)`.
71/// Otherwise, returns `(nullptr, nullptr)`.
72template<class N>
73std::tuple<const Extract*, N*> isa_var_proj(const Def* def) {
74 if (auto proj = def->isa<Extract>())
75 if (auto var = proj->tuple()->isa<Var>(); var && var->binder()->isa<N>()) return {proj, var->binder()->as<N>()};
76 return {nullptr, nullptr};
77}
78///@}
79
80/// @name Closure Types
81///@{
82/// Returns @p def if @p def is a closure and @c nullptr otherwise
83const Sigma* isa_clos_type(const Def* def);
84
85/// Creates a typed closure type from @p pi.
86Sigma* clos_type(const Pi* pi);
87
88/// Convert a closure type to a Pi, where the environment type has been removed or replaced by @p new_env_type
89/// (if @p new_env_type != @c nullptr)
90const Pi* clos_type_to_pi(const Def* ct, const Def* new_env_type = nullptr);
91
92///@}
93
94/// @name Closure Environment
95///@{
96/// `tup_or_sig` should generally be a Tuple, Sigma or Var.
97
98/// Describes where the environment is placed in the argument list: right after a leading `mem.M`, if @p doms
99/// starts with one, or in slot 0 otherwise. This way, closures built from mem-free (pure) functions don't gain
100/// a bogus mem-shaped layout, and don't get misaligned with their real parameters (see issue #126).
101inline size_t env_param(Defs doms) { return (!doms.empty() && Axm::isa<mem::M>(doms.front())) ? 1_u64 : 0_u64; }
102inline size_t env_param(const Pi* pi) { return env_param(pi->doms()); }
103
104/// Adjust the index of an argument to account for the env param.
105inline size_t shift_env(size_t ep, size_t i) { return (i < ep) ? i : i - 1_u64; }
106
107/// Same as shift_env, but skips the env param instead.
108inline size_t skip_env(size_t ep, size_t i) { return (i < ep) ? i : i + 1_u64; }
109
110/// Builds a closure type from the domains @p doms of a `Cn`.
111/// If @p env_type is `nullptr`, returns the recursive closure Sigma `[T: *, Cn [doms with T at env_param], T]`.
112/// Otherwise, returns the bare `Cn [doms with env_type at env_param]` (the code part of such a closure).
113const Def* ctype(World& w, Defs doms, const Def* env_type = nullptr);
114
115const Def* clos_insert_env(size_t ep, size_t i, const Def* env, std::function<const Def*(size_t)> f);
116inline const Def* clos_insert_env(size_t ep, size_t i, const Def* env, const Def* a) {
117 return clos_insert_env(ep, i, env, [&](auto i) { return a->proj(i); });
118}
119
120inline const Def* clos_insert_env(size_t ep, const Def* env, const Def* tup_or_sig) {
121 auto& w = tup_or_sig->world();
122 auto new_ops = DefVec(tup_or_sig->num_projs() + 1, [&](auto i) { return clos_insert_env(ep, i, env, tup_or_sig); });
123 return (tup_or_sig->isa<Sigma>()) ? w.sigma(new_ops) : w.tuple(new_ops);
124}
125
126const Def* clos_remove_env(size_t ep, size_t i, std::function<const Def*(size_t)> f);
127inline const Def* clos_remove_env(size_t ep, size_t i, const Def* def) {
128 return clos_remove_env(ep, i, [&](auto i) { return def->proj(i); });
129}
130inline const Def* clos_remove_env(size_t ep, const Def* tup_or_sig) {
131 auto& w = tup_or_sig->world();
132 auto new_ops = DefVec(tup_or_sig->num_projs() - 1, [&](auto i) { return clos_remove_env(ep, i, tup_or_sig); });
133 return (tup_or_sig->isa<Sigma>()) ? w.sigma(new_ops) : w.tuple(new_ops);
134}
135
136inline const Def* clos_sub_env(size_t ep, const Def* tup_or_sig, const Def* new_env) {
137 auto& w = tup_or_sig->world();
138 auto new_ops = DefVec(tup_or_sig->num_projs(), [&](auto i) { return i == ep ? new_env : tup_or_sig->proj(i); });
139 return (tup_or_sig->isa<Sigma>()) ? w.sigma(new_ops) : w.tuple(new_ops);
140}
141///@}
142
143} // namespace mim::plug::clos
static auto isa(const Def *def)
Definition axm.h:112
Base class for all Defs.
Definition def.h:273
const Def * proj(nat_t a, nat_t i) const
Similar to World::extract while assuming an arity of a, but also works on Sigmas and Arrays.
Definition def.cpp:623
World & world() const noexcept
Definition def.h:1097
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:1111
nat_t num_projs() const
Yields Def::arity(), if it is a Lit, or 1 otherwise.
Definition def.h:1132
Extracts from a Sigma or Array-typed Extract::tuple the element at position Extract::index.
Definition tuple.h:161
A function.
Definition lam.h:113
const Def * ret_var()
Yields the Lam::var of the Lam::ret_pi.
Definition lam.h:159
A dependent function type.
Definition lam.h:14
static const Pi * isa_basicblock(const Def *d)
Is this a continuation (Pi::isa_cn) that is not Pi::isa_returning?
Definition lam.h:56
static const Pi * isa_returning(const Def *d)
Is this a continuation (Pi::isa_cn) which has a Pi::ret_pi?
Definition lam.h:51
A dependent tuple type.
Definition tuple.h:23
Data constructor for a Sigma.
Definition tuple.h:61
A variable introduced by a binder (mutable).
Definition def.h:825
Def * binder() const
The binder of this Var.
Definition def.h:835
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:40
const Def * tuple(Defs ops)
Definition world.cpp:326
Lightweight, non-owning view onto a closure literal (env_type, fn, env); see isa_clos_lit.
Definition clos.h:15
const Sigma * type() const
Definition clos.h:19
const Def * ret_var() const
Definition clos.h:29
const Def * env_type() const
Definition clos.h:22
const Def * fnc() const
Definition clos.cpp:39
const Pi * fnc_type() const
Definition clos.h:25
Lam * fnc_as_lam() const
Definition clos.cpp:41
const Tuple * operator->() const
Definition clos.h:36
bool is_basicblock() const
Definition clos.h:39
const Def * env_var() const
Definition clos.cpp:47
bool is_returning() const
Definition clos.h:38
friend ClosLit isa_clos_lit(const Def *, bool)
Tries to match a closure literal.
Definition clos.cpp:52
const Def * env() const
Definition clos.cpp:37
The clos Plugin
Definition clos.h:9
ClosLit isa_clos_lit(const Def *def, bool fn_isa_lam=true)
Tries to match a closure literal.
Definition clos.cpp:52
const Def * clos_sub_env(size_t ep, const Def *tup_or_sig, const Def *new_env)
Definition clos.h:136
const Def * clos_remove_env(size_t ep, size_t i, std::function< const Def *(size_t)> f)
Definition clos.cpp:124
Sigma * clos_type(const Pi *pi)
Creates a typed closure type from pi.
Definition clos.cpp:101
size_t shift_env(size_t ep, size_t i)
Adjust the index of an argument to account for the env param.
Definition clos.h:105
const Def * ctype(World &w, Defs doms, const Def *env_type=nullptr)
Builds a closure type from the domains doms of a Cn.
Definition clos.cpp:126
const Def * clos_insert_env(size_t ep, size_t i, const Def *env, std::function< const Def *(size_t)> f)
Definition clos.cpp:120
const Pi * clos_type_to_pi(const Def *ct, const Def *new_env_type=nullptr)
Convert a closure type to a Pi, where the environment type has been removed or replaced by new_env_ty...
Definition clos.cpp:107
const Def * apply_closure(const Def *closure, Defs args)
Definition clos.h:66
std::tuple< const Def *, const Def *, const Def * > clos_unpack(const Def *c)
Deconstruct a closure into (env_type, function, env).
Definition clos.cpp:72
std::tuple< const Extract *, N * > isa_var_proj(const Def *def)
If def is a projection var#i of the Var of some mutable of type N, returns (projection,...
Definition clos.h:73
size_t skip_env(size_t ep, size_t i)
Same as shift_env, but skips the env param instead.
Definition clos.h:108
const Def * clos_pack(const Def *env, const Def *fn, const Def *ct=nullptr)
Pack a typed closure.
Definition clos.cpp:61
const Def * clos_apply(const Def *closure, const Def *args)
Apply a closure to arguments.
Definition clos.cpp:78
const Sigma * isa_clos_type(const Def *def)
Definition clos.cpp:90
size_t env_param(Defs doms)
Describes where the environment is placed in the argument list: right after a leading mem....
Definition clos.h:101
fe::View< const Def * > Defs
Definition def.h:91
fe::Vector< const Def * > DefVec
Definition def.h:93