19 m(Type, type) m(Univ, univ) m(UMax, umax) m(UInc, uinc) \
20 m(Pi, pi) m(Lam, lam) m(App, app) \
21 m(Sigma, sigma) m(Tuple, tuple) m(Extract, extract) m(Insert, insert) \
22 m(Arr, arr) m(Pack, pack) \
23 m(Join, join) m(Vel, vel) m(Test, test) m(Top, top) \
24 m(Meet, meet) m(Ac, ac ) m(Pick, pick) m(Bot, bot) \
28 m(Nat, nat) m(Idx, idx) \
39#define CODE(node, name) node,
43#define CODE(node, name) +size_t(1)
94 operator const Def*()
const {
return refer(def_); }
95 explicit operator bool()
const {
return def_; }
97 const Def*
def()
const {
return def_; }
102 const Def* def_ =
nullptr;
117using fe::operator<=>;
123enum class Dep :
unsigned {
135template<>
struct fe::is_bit_enum<
mim::
Dep> : std::true_type {};
141#define MIM_PROJ(NAME, CONST) \
142 nat_t num_##NAME##s() CONST noexcept { return ((const Def*)NAME())->num_projs(); } \
143 nat_t num_t##NAME##s() CONST noexcept { return ((const Def*)NAME())->num_tprojs(); } \
144 Ref NAME(nat_t a, nat_t i) CONST noexcept { return ((const Def*)NAME())->proj(a, i); } \
145 Ref NAME(nat_t i) CONST noexcept { return ((const Def*)NAME())->proj(i); } \
146 Ref t##NAME(nat_t i) CONST noexcept { return ((const Def*)NAME())->tproj(i); } \
147 template<nat_t A = std::dynamic_extent, class F> auto NAME##s(F f) CONST noexcept { \
148 return ((const Def*)NAME())->projs<A, F>(f); \
150 template<class F> auto t##NAME##s(F f) CONST noexcept { return ((const Def*)NAME())->tprojs<F>(f); } \
151 template<nat_t A = std::dynamic_extent> auto NAME##s() CONST noexcept { return ((const Def*)NAME())->projs<A>(); } \
152 auto t##NAME##s() CONST noexcept { return ((const Def*)NAME())->tprojs(); } \
153 template<class F> auto NAME##s(nat_t a, F f) CONST noexcept { return ((const Def*)NAME())->projs<F>(a, f); } \
154 auto NAME##s(nat_t a) CONST noexcept { return ((const Def*)NAME())->projs(a); }
157template<
class P,
class D = Def>
class Setters {
159 P* super() {
return static_cast<P*
>(
this); }
160 const P* super()
const {
return static_cast<const P*
>(
this); }
164 template<
bool Ow = false>
const P*
set(Loc l )
const { super()->D::template
set<Ow>(l);
return super(); }
165 template<
bool Ow = false> P*
set(Loc l ) { super()->D::template
set<Ow>(l);
return super(); }
166 template<
bool Ow = false>
const P*
set( Sym s )
const { super()->D::template
set<Ow>(s);
return super(); }
167 template<
bool Ow = false> P*
set( Sym s ) { super()->D::template
set<Ow>(s);
return super(); }
168 template<
bool Ow = false>
const P*
set( std::string s)
const { super()->D::template
set<Ow>(std::move(s));
return super(); }
169 template<
bool Ow = false> P*
set( std::string s) { super()->D::template
set<Ow>(std::move(s));
return super(); }
170 template<
bool Ow = false>
const P*
set(Loc l, Sym s )
const { super()->D::template
set<Ow>(l, s);
return super(); }
171 template<
bool Ow = false> P*
set(Loc l, Sym s ) { super()->D::template
set<Ow>(l, s);
return super(); }
172 template<
bool Ow = false>
const P*
set(Loc l, std::string s)
const { super()->D::template
set<Ow>(l, std::move(s));
return super(); }
173 template<
bool Ow = false> P*
set(Loc l, std::string s) { super()->D::template
set<Ow>(l, std::move(s));
return super(); }
174 template<
bool Ow = false>
const P*
set(
Dbg d )
const { super()->D::template
set<Ow>(d);
return super(); }
175 template<
bool Ow = false> P*
set(
Dbg d ) { super()->D::template
set<Ow>(d);
return super(); }
212class Def :
public fe::RuntimeCast<Def> {
214 Def& operator=(
const Def&) =
delete;
231 constexpr u32 gid() const noexcept {
return gid_; }
232 constexpr size_t hash() const noexcept {
return hash_; }
254 assert(a.has_value());
261 template<
size_t N = std::dynamic_extent>
constexpr auto ops() const noexcept {
264 Ref op(
size_t i)
const noexcept {
return ops()[i]; }
265 constexpr size_t num_ops() const noexcept {
return num_ops_; }
315 bool has_dep(
unsigned u)
const {
return dep_ & u; }
347 template<nat_t A = std::dynamic_extent,
class F>
auto projs(F f)
const {
348 using R = std::decay_t<
decltype(f(
this))>;
349 if constexpr (A == std::dynamic_extent) {
353 std::array<R, A> array;
354 for (
nat_t i = 0; i != A; ++i) array[i] = f(
proj(A, i));
362 using R = std::decay_t<
decltype(f(
this))>;
365 template<nat_t A = std::dynamic_extent>
auto projs()
const {
369 return tprojs([](
Ref def) {
return *def; });
372 return projs(a, [](
Ref def) {
return *def; });
432 template<
class T = Def,
bool invert = false> T*
isa_mut()
const {
433 if constexpr (std::is_same<T, Def>::value)
434 return mut_ ^ invert ?
const_cast<Def*
>(
this) :
nullptr;
436 return mut_ ^ invert ?
const_cast<Def*
>(
this)->
template isa<T>() :
nullptr;
440 template<
class T = Def,
bool invert = false> T*
as_mut()
const {
441 assert(mut_ ^ invert);
442 if constexpr (std::is_same<T, Def>::value)
443 return const_cast<Def*
>(
this);
445 return const_cast<Def*
>(
this)->
template as<T>();
465 template<
bool Ow = false>
const Def*
set( std::string s)
const {
set(
sym(std::move(s)));
return this; }
466 template<
bool Ow = false>
Def*
set( std::string s) {
set(
sym(std::move(s)));
return this; }
467 template<
bool Ow = false>
const Def*
set(Loc l, Sym s )
const {
set(l);
set(s);
return this; }
468 template<
bool Ow = false>
Def*
set(Loc l, Sym s ) {
set(l);
set(s);
return this; }
469 template<
bool Ow = false>
const Def*
set(Loc l, std::string s)
const {
set(l);
set(
sym(std::move(s)));
return this; }
470 template<
bool Ow = false>
Def*
set(Loc l, std::string s) {
set(l);
set(
sym(std::move(s)));
return this; }
471 template<
bool Ow = false>
const Def*
set(
Dbg d)
const {
set(d.loc(), d.sym());
return this; }
472 template<
bool Ow = false>
Def*
set(
Dbg d) {
set(d.loc(), d.sym());
return this; }
484 const Def*
debug_suffix(std::string)
const {
return this; }
524 void dump(
int max)
const;
525 void write(
int max)
const;
526 void write(
int max,
const char* file)
const;
527 std::ostream&
stream(std::ostream&,
int max)
const;
534 void dot(std::ostream& os, uint32_t max = 0xFFFFFF,
bool types =
false)
const;
536 void dot(
const char* file =
nullptr, uint32_t max = 0xFFFFFF,
bool types =
false)
const;
537 void dot(
const std::string& file, uint32_t max = 0xFFFFFF,
bool types =
false)
const {
538 return dot(file.c_str(), max, types);
546 Sym
sym(
const char*)
const;
547 Sym
sym(std::string_view)
const;
548 Sym
sym(std::string)
const;
558 const Def** ops_ptr()
const {
559 return reinterpret_cast<const Def**
>(
reinterpret_cast<char*
>(
const_cast<Def*
>(
this + 1)));
561 bool equal(
const Def* other)
const;
569 mutable World* world_;
599using DefDef = std::tuple<const Def*, const Def*>;
603 if constexpr (
sizeof(size_t) == 8)
614template<
class To>
using DefDefMap = absl::flat_hash_map<DefDef, To, DefDefHash, DefDefEq>;
615using DefDefSet = absl::flat_hash_set<DefDef, DefDefHash, DefDefEq>;
719 template<
class T = flags_t> T
get()
const {
720 static_assert(
sizeof(T) <= 8);
731 template<
class T = nat_t>
static std::optional<T>
isa(
Ref def) {
733 if (
auto lit = def->isa<
Lit>())
return lit->get<T>();
736 template<
class T = nat_t>
static T
as(
Ref def) {
return def->as<
Lit>()->
get<T>(); }
784 assert(res.has_value());
bool is_set() const
Yields true if empty or the last op is set.
Ref op(size_t i) const noexcept
const Def * set(Dbg d) const
void dot(std::ostream &os, uint32_t max=0xFFFFFF, bool types=false) const
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
const Var * has_var() const
As above if this is a mutable.
Ref var()
Not necessarily a Var: E.g., if the return type is [], this will yield ().
const T * isa_imm(R(T::*f)() const) const
bool has_dep(Dep d) const
nat_t num_tprojs() const
As above but yields 1, if Flags::scalarize_threshold is exceeded.
nat_t as_lit_arity() const
bool has_dep(unsigned u) const
World & world() const noexcept
Muts mut_local_muts()
All local_muts() of this mutable's deps().
void dot(const std::string &file, uint32_t max=0xFFFFFF, bool types=false) const
std::string_view node_name() const
auto projs(nat_t a, F f) const
Ref tproj(nat_t i) const
As above but takes Def::num_tprojs.
constexpr auto ops() const noexcept
Vars local_vars() const
Vars reachable by following immutable deps().
Ref unfold_type() const
Yields the type of this Def and builds a new Type (UInc n) if necessary.
constexpr flags_t flags() const noexcept
Def * set(size_t i, Ref)
Successively set from left to right.
const Def * set(std::string s) const
T * isa_mut() const
If this is *mut*able, it will cast constness away and perform a dynamic_cast to T.
DefVec reduce(Ref arg) const
Rewrites Def::ops by substituting this mutable's Var with arg.
Def * stub(World &w, Ref type)
auto projs(nat_t a) const
friend std::ostream & operator<<(std::ostream &, const Def *)
This will stream def as an operand.
bool is_term() const
Yields true if this:T and T:(Type 0).
bool has_const_dep() const
Neither a Dep::Mut nor a Dep::Var; can often be used as shortcut as an optimization.
const Def * debug_prefix(std::string) const
bool is_immutabilizable()
void transfer_external(Def *to)
Def * reset(size_t i, Ref def)
Successively reset from left to right.
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
virtual Def * stub_(World &, Ref)
bool is_open() const
Has free_vars()?
constexpr size_t hash() const noexcept
virtual const Def * immutabilize()
Tries to make an immutable from a mutable.
Ref rebuild(Ref type, Defs ops) const
Muts local_muts() const
Mutables reachable by following immutable deps(); mut->local_muts() is by definition the set { mut }...
Ref type() const noexcept
Yields the raw type of this Def, i.e. maybe nullptr.
const Def * debug_suffix(std::string) const
const Def * set(Sym s) const
Ref proj(nat_t i) const
As above but takes Def::num_projs as arity.
const Def * set(Loc l, Sym s) const
virtual Ref check(size_t, Ref def)
const Def * set(Loc l) const
void write(int max) const
constexpr node_t node() const noexcept
Def * set(Loc l, std::string s)
virtual Ref rebuild_(World &w, Ref type, Defs ops) const =0
nat_t num_projs() const
Yields Def::as_lit_arity(), if it is in fact a Lit, or 1 otherwise.
std::optional< nat_t > isa_lit_arity() const
std::ostream & stream(std::ostream &, int max) const
friend void swap(World &, World &) noexcept
Ref rebuild(World &w, Ref type, Defs ops) const
Def::rebuilds this Def while using new_op as substitute for its i'th Def::op.
Ref 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.
constexpr u32 gid() const noexcept
Def * unset()
Unsets all Def::ops; works even, if not set at all or partially.
std::string unique_name() const
name + "_" + Def::gid
const Def * set(Loc l, std::string s) const
const T * isa_imm() const
Muts users()
Set of mutables where this mutable is locally referenced.
Ref refine(size_t i, Ref new_op) const
bool is_closed() const
Has no free_vars()?
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
constexpr size_t num_ops() const noexcept
Ref rebuild_(World &, Ref, Defs) const override
Global * stub_(World &, Ref) override
static constexpr auto Node
A built-in constant of type Nat -> *.
static constexpr auto Node
static constexpr nat_t size2bitwidth(nat_t n)
static constexpr nat_t bitwidth2size(nat_t n)
static Ref isa(Ref def)
Checks if def is a Idx s and returns s or nullptr otherwise.
static nat_t as_lit(Ref def)
Ref rebuild_(World &, Ref, Defs) const override
static std::optional< nat_t > isa_lit(Ref def)
This node is a hole in the IR that is inferred by its context later on.
Ref rebuild_(World &, Ref, Defs) const override
static std::optional< T > isa(Ref def)
static constexpr auto Node
Ref rebuild_(World &, Ref, Defs) const override
static constexpr auto Node
Ref rebuild_(World &, Ref, Defs) const override
static constexpr auto Node
u32 pass() const
IPass::index within PassMan.
Helper class to retrieve Infer::arg if present.
const Def * operator*() const
const Def * def() const
Retrieve wrapped Def without Infer::refering.
static const Def * refer(const Def *def)
Same as Infer::find but does nothing if def is nullptr.
const Def * operator->() const
friend std::ostream & operator<<(std::ostream &, Ref)
CRTP-based Mixin to declare setters for Def::loc & Def::name using a covariant return type.
const P * set(Sym s) const
const P * set(Loc l, Sym s) const
const P * set(Loc l) const
const P * set(Dbg d) const
const P * set(Loc l, std::string s) const
P * set(Loc l, std::string s)
const P * set(std::string s) const
This is a thin wrapper for std::span<T, N> with the following additional features:
Ref rebuild_(World &, Ref, Defs) const override
static constexpr auto Node
static constexpr auto Node
Ref rebuild_(World &, Ref, Defs) const override
static constexpr auto Node
Ref rebuild_(World &, Ref, Defs) const override
static constexpr auto Node
Ref rebuild_(World &, Ref, Defs) const override
static constexpr auto Node
Ref rebuild_(World &, Ref, Defs) const override
The World represents the whole program and manages creation of MimIR nodes (Defs).
#define MIM_PROJ(NAME, CONST)
Use as mixin to wrap all kind of Def::proj and Def::projs variants.
DefMap< const Def * > Def2Def
absl::flat_hash_map< DefDef, To, DefDefHash, DefDefEq > DefDefMap
D bitcast(const S &src)
A bitcast from src of type S to D.
std::tuple< const Def *, const Def * > DefDef
absl::flat_hash_set< K, GIDHash< K >, GIDEq< K > > GIDSet
GIDSet< const Var * > VarSet
GIDMap< const Var *, To > VarMap
GIDMap< const Def *, To > DefMap
size_t hash_combine(size_t seed, T v)
absl::flat_hash_map< K, V, GIDHash< K >, GIDEq< K > > GIDMap
GIDSet< const Def * > DefSet
PooledSet< const Var * > Vars
absl::flat_hash_set< DefDef, DefDefHash, DefDefEq > DefDefSet
Ref(*)(Ref, Ref, Ref) NormalizeFn
Vector(I, I, A=A()) -> Vector< typename std::iterator_traits< I >::value_type, Default_Inlined_Size< typename std::iterator_traits< I >::value_type >, A >
GIDMap< Def *, To > MutMap
VarMap< const Var * > Var2Var
constexpr decltype(auto) get(mim::Span< T, N > span)
bool operator()(DefDef p1, DefDef p2) const
size_t operator()(DefDef pair) const