MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
world.h
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4#include <string_view>
5#include <type_traits>
6
7#include <absl/container/btree_map.h>
8#include <absl/container/btree_set.h>
9#include <fe/arena.h>
10
11#include "mim/axiom.h"
12#include "mim/check.h"
13#include "mim/flags.h"
14#include "mim/lam.h"
15#include "mim/lattice.h"
16#include "mim/tuple.h"
17
18#include "mim/util/dbg.h"
19#include "mim/util/log.h"
20
21namespace mim {
22class Driver;
23
24/// The World represents the whole program and manages creation of MimIR nodes (Def%s).
25/// Def%s are hashed into an internal HashSet.
26/// The World's factory methods just calculate a hash and lookup the Def, if it is already present, or create a new one
27/// otherwise. This corresponds to value numbering.
28///
29/// You can create several worlds.
30/// All worlds are completely independent from each other.
31///
32/// Note that types are also just Def%s and will be hashed as well.
33class World {
34public:
35 /// @name State
36 ///@{
37 struct State {
38 State() = default;
39
40 /// [Plain Old Data](https://en.cppreference.com/w/cpp/named_req/PODType)
41 struct POD {
44 Loc loc;
45 Sym name;
46 mutable bool frozen = false;
47 } pod;
48
49#ifdef MIM_ENABLE_CHECKS
50 absl::flat_hash_set<uint32_t> breakpoints;
51#endif
52 friend void swap(State& s1, State& s2) noexcept {
53 using std::swap;
54 assert((!s1.pod.loc || !s2.pod.loc) && "Why is get_loc() still set?");
55 swap(s1.pod, s2.pod);
56#ifdef MIM_ENABLE_CHECKS
57 swap(s1.breakpoints, s2.breakpoints);
58#endif
59 }
60 };
61
62 /// @name C'tor and D'tor
63 ///@{
64 World& operator=(World) = delete;
65
66 /// Inherits the @p state into the new World.
67 explicit World(Driver*);
68 World(Driver*, const State&);
69 World(World&& other) noexcept
70 : World(&other.driver(), other.state()) {
71 swap(*this, other);
72 }
73 World inherit() { return World(&driver(), state()); }
74 ~World();
75 ///@}
76
77 /// @name Getters/Setters
78 ///@{
79 const State& state() const { return state_; }
80
81 const Driver& driver() const { return *driver_; }
82 Driver& driver() { return *driver_; }
83
84 Sym name() const { return state_.pod.name; }
85 void set(Sym name) { state_.pod.name = name; }
86 void set(std::string_view name) { state_.pod.name = sym(name); }
87
88 /// Manage global identifier - a unique number for each Def.
89 u32 curr_gid() const { return state_.pod.curr_gid; }
90 u32 next_gid() { return ++state_.pod.curr_gid; }
91
92 /// Retrive compile Flags.
93 Flags& flags();
94 ///@}
95
96 /// @name Loc
97 ///@{
98 struct ScopedLoc {
99 ScopedLoc(World& world, Loc old_loc)
100 : world_(world)
101 , old_loc_(old_loc) {}
102 ~ScopedLoc() { world_.set_loc(old_loc_); }
103
104 private:
105 World& world_;
106 Loc old_loc_;
107 };
108
109 Loc get_loc() const { return state_.pod.loc; }
110 void set_loc(Loc loc = {}) { state_.pod.loc = loc; }
111 ScopedLoc push(Loc loc) {
112 auto sl = ScopedLoc(*this, get_loc());
113 set_loc(loc);
114 return sl;
115 }
116 ///@}
117
118 /// @name Sym
119 ///@{
120 Sym sym(std::string_view);
121 Sym sym(const char*);
122 Sym sym(const std::string&);
123 /// Appends a @p suffix or an increasing number if the suffix already exists.
124 Sym append_suffix(Sym name, std::string suffix);
125 ///@}
126
127 /// @name Freeze
128 /// In frozen state the World does not create any nodes.
129 ///@{
130 bool is_frozen() const { return state_.pod.frozen; }
131
132 /// Yields old frozen state.
133 bool freeze(bool on = true) const {
134 bool old = state_.pod.frozen;
135 state_.pod.frozen = on;
136 return old;
137 }
138
139 /// Use to World::freeze and automatically unfreeze at the end of scope.
140 struct Freezer {
142 : world(world)
143 , old(world.freeze(true)) {}
145
146 const World& world;
147 bool old;
148 };
149 ///@}
150
151 /// @name Debugging Features
152 ///@{
153#ifdef MIM_ENABLE_CHECKS
154 const auto& breakpoints() { return state_.breakpoints; }
155
156 Ref gid2def(u32 gid); ///< Lookup Def by @p gid.
157 void breakpoint(u32 gid); ///< Trigger breakpoint in your debugger when creating Def with Def::gid @p gid.
158
159 World& verify(); ///< Verifies that all externals() and annexes() are Def::is_closed(), if `MIM_ENABLE_CHECKS`.
160#else
161 World& verify() { return *this; }
162#endif
163 ///@}
164
165 /// @name Manage Nodes
166 ///@{
167 const auto& annexes() const { return move_.annexes; }
168 const auto& externals() const { return move_.externals; }
169 void make_external(Def* def) {
170 assert(!def->is_external());
171 assert(def->is_closed());
172 def->external_ = true;
173 assert_emplace(move_.externals, def->sym(), def);
174 }
175 void make_internal(Def* def) {
176 assert(def->is_external());
177 def->external_ = false;
178 auto num = move_.externals.erase(def->sym());
179 assert_unused(num == 1);
180 }
181
182 Def* external(Sym name) { return mim::lookup(move_.externals, name); } ///< Lookup by @p name.
183
184 /// Lookup annex by Axiom::id.
185 template<class Id> const Def* annex(Id id) {
186 auto flags = static_cast<flags_t>(id);
187 if (auto i = move_.annexes.find(flags); i != move_.annexes.end()) return i->second;
188 error("Axiom with ID '{x}' not found; demangled plugin name is '{}'", flags, Annex::demangle(driver(), flags));
189 }
190
191 /// Get Axiom from a plugin.
192 /// Can be used to get an Axiom without sub-tags.
193 /// E.g. use `w.annex<mem::M>();` to get the `%mem.M` Axiom.
194 template<annex_without_subs id> const Def* annex() { return annex(Annex::Base<id>); }
195
196 const Def* register_annex(flags_t f, const Def*);
197 const Def* register_annex(plugin_t p, tag_t t, sub_t s, const Def* def) {
198 return register_annex(p | (flags_t(t) << 8_u64) | flags_t(s), def);
199 }
200 ///@}
201
202 /// @name Univ, Type, Var, Proxy, Infer
203 ///@{
204 const Univ* univ() { return data_.univ; }
205 Ref uinc(Ref op, level_t offset = 1);
206 template<Sort = Sort::Univ> Ref umax(Defs);
207 const Type* type(Ref level);
208 const Type* type_infer_univ() { return type(mut_infer_univ()); }
209 template<level_t level = 0> const Type* type() {
210 if constexpr (level == 0)
211 return data_.type_0;
212 else if constexpr (level == 1)
213 return data_.type_1;
214 else
215 return type(lit_univ(level));
216 }
217 Ref var(Ref type, Def* mut);
218 const Proxy* proxy(Ref type, Defs ops, u32 index, u32 tag) {
219 return unify<Proxy>(ops.size(), type, ops, index, tag);
220 }
221
225
226 /// Either a value `?:?:.Type ?` or a type `?:.Type ?:.Type ?`.
228 auto t = type_infer_univ();
229 auto res = mut_infer(mut_infer(t));
230 assert(this == &res->world());
231 return res;
232 }
233 ///@}
234
235 /// @name Axiom
236 ///@{
237 const Axiom* axiom(NormalizeFn n, u8 curry, u8 trip, Ref type, plugin_t p, tag_t t, sub_t s) {
238 return unify<Axiom>(0, n, curry, trip, type, p, t, s);
239 }
240 const Axiom* axiom(Ref type, plugin_t p, tag_t t, sub_t s) { return axiom(nullptr, 0, 0, type, p, t, s); }
241
242 /// Builds a fresh Axiom with descending Axiom::sub.
243 /// This is useful during testing to come up with some entitiy of a specific type.
244 /// It uses the plugin Axiom::Global_Plugin and starts with `0` for Axiom::sub and counts up from there.
245 /// The Axiom::tag is set to `0` and the Axiom::normalizer to `nullptr`.
246 const Axiom* axiom(NormalizeFn n, u8 curry, u8 trip, Ref type) {
247 return axiom(n, curry, trip, type, Annex::Global_Plugin, 0, state_.pod.curr_sub++);
248 }
249 const Axiom* axiom(Ref type) { return axiom(nullptr, 0, 0, type); } ///< See above.
250 ///@}
251
252 /// @name Pi
253 ///@{
254 // clang-format off
255 const Pi* pi(Ref dom, Ref codom, bool implicit = false) { return unify<Pi>(2, Pi::infer(dom, codom), dom, codom, implicit); }
256 const Pi* pi(Defs dom, Ref codom, bool implicit = false) { return pi(sigma(dom), codom, implicit); }
257 const Pi* pi(Ref dom, Defs codom, bool implicit = false) { return pi(dom, sigma(codom), implicit); }
258 const Pi* pi(Defs dom, Defs codom, bool implicit = false) { return pi(sigma(dom), sigma(codom), implicit); }
259 Pi* mut_pi(Ref type, bool implicit = false) { return insert<Pi>(2, type, implicit); }
260 // clang-format on
261 ///@}
262
263 /// @name Cn
264 /// Pi with codom mim::Bot%tom
265 ///@{
266 // clang-format off
267 const Pi* cn( ) { return cn(sigma( ), false); }
268 const Pi* cn(Ref dom, bool implicit = false) { return pi( dom , type_bot(), implicit); }
269 const Pi* cn(Defs dom, bool implicit = false) { return cn(sigma(dom), implicit); }
270 const Pi* fn(Ref dom, Ref codom, bool implicit = false) { return cn({ dom , cn(codom)}, implicit); }
271 const Pi* fn(Defs dom, Ref codom, bool implicit = false) { return fn(sigma(dom), codom, implicit); }
272 const Pi* fn(Ref dom, Defs codom, bool implicit = false) { return fn( dom , sigma(codom), implicit); }
273 const Pi* fn(Defs dom, Defs codom, bool implicit = false) { return fn(sigma(dom), sigma(codom), implicit); }
274 // clang-format on
275 ///@}
276
277 /// @name Lam
278 ///@{
280 if (auto b = std::get_if<bool>(&filter)) return lit_bool(*b);
282 }
283 const Lam* lam(const Pi* pi, Lam::Filter f, Ref body) { return unify<Lam>(2, pi, filter(f), body); }
284 Lam* mut_lam(const Pi* pi) { return insert<Lam>(2, pi); }
285 // clang-format off
286 const Lam* con(Ref dom, Lam::Filter f, Ref body) { return unify<Lam>(2, cn(dom ), filter(f), body); }
287 const Lam* con(Defs dom, Lam::Filter f, Ref body) { return unify<Lam>(2, cn(dom ), filter(f), body); }
288 const Lam* lam(Ref dom, Ref codom, Lam::Filter f, Ref body) { return unify<Lam>(2, pi(dom, codom), filter(f), body); }
289 const Lam* lam(Defs dom, Ref codom, Lam::Filter f, Ref body) { return unify<Lam>(2, pi(dom, codom), filter(f), body); }
290 const Lam* lam(Ref dom, Defs codom, Lam::Filter f, Ref body) { return unify<Lam>(2, pi(dom, codom), filter(f), body); }
291 const Lam* lam(Defs dom, Defs codom, Lam::Filter f, Ref body) { return unify<Lam>(2, pi(dom, codom), filter(f), body); }
292 const Lam* fun(Ref dom, Ref codom, Lam::Filter f, Ref body) { return unify<Lam>(2, fn(dom , codom), filter(f), body); }
293 const Lam* fun(Defs dom, Ref codom, Lam::Filter f, Ref body) { return unify<Lam>(2, fn(dom, codom), filter(f), body); }
294 const Lam* fun(Ref dom, Defs codom, Lam::Filter f, Ref body) { return unify<Lam>(2, fn(dom, codom), filter(f), body); }
295 const Lam* fun(Defs dom, Defs codom, Lam::Filter f, Ref body) { return unify<Lam>(2, fn(dom, codom), filter(f), body); }
296 Lam* mut_con(Ref dom ) { return insert<Lam>(2, cn(dom )); }
297 Lam* mut_con(Defs dom ) { return insert<Lam>(2, cn(dom )); }
298 Lam* mut_lam(Ref dom, Ref codom) { return insert<Lam>(2, pi(dom, codom)); }
299 Lam* mut_lam(Defs dom, Ref codom) { return insert<Lam>(2, pi(dom, codom)); }
300 Lam* mut_lam(Ref dom, Defs codom) { return insert<Lam>(2, pi(dom, codom)); }
301 Lam* mut_lam(Defs dom, Defs codom) { return insert<Lam>(2, pi(dom, codom)); }
302 Lam* mut_fun(Ref dom, Ref codom) { return insert<Lam>(2, fn(dom, codom)); }
303 Lam* mut_fun(Defs dom, Ref codom) { return insert<Lam>(2, fn(dom, codom)); }
304 Lam* mut_fun(Ref dom, Defs codom) { return insert<Lam>(2, fn(dom, codom)); }
305 Lam* mut_fun(Defs dom, Defs codom) { return insert<Lam>(2, fn(dom, codom)); }
306 // clang-format on
307 Lam* exit() { return data_.exit; } ///< Used as a dummy exit node within Scope.
308 ///@}
309
310 /// @name App
311 ///@{
312 Ref app(Ref callee, Ref arg);
313 Ref app(Ref callee, Defs args) { return app(callee, tuple(args)); }
314 template<bool Normalize = false> Ref raw_app(Ref type, Ref callee, Ref arg);
315 template<bool Normalize = false> Ref raw_app(Ref type, Ref callee, Defs args) {
316 return raw_app<Normalize>(type, callee, tuple(args));
317 }
318 ///@}
319
320 /// @name Sigma
321 ///@{
322 Sigma* mut_sigma(Ref type, size_t size) { return insert<Sigma>(size, type, size); }
323 /// A *mut*able Sigma of type @p level.
324 template<level_t level = 0> Sigma* mut_sigma(size_t size) { return mut_sigma(type<level>(), size); }
325 Ref sigma(Defs ops);
326 const Sigma* sigma() { return data_.sigma; } ///< The unit type within Type 0.
327 ///@}
328
329 /// @name Arr
330 ///@{
331 Arr* mut_arr(Ref type) { return insert<Arr>(2, type); }
332 template<level_t level = 0> Arr* mut_arr() { return mut_arr(type<level>()); }
333 Ref arr(Ref shape, Ref body);
334 Ref arr(Defs shape, Ref body);
335 Ref arr(u64 n, Ref body) { return arr(lit_nat(n), body); }
336 Ref arr(View<u64> shape, Ref body) {
337 return arr(DefVec(shape.size(), [&](size_t i) { return lit_nat(shape[i]); }), body);
338 }
339 Ref arr_unsafe(Ref body) { return arr(top_nat(), body); }
340 ///@}
341
342 /// @name Tuple
343 ///@{
344 Ref tuple(Defs ops);
345 /// Ascribes @p type to this tuple - needed for dependently typed and mutable Sigma%s.
346 Ref tuple(Ref type, Defs ops);
347 const Tuple* tuple() { return data_.tuple; } ///< the unit value of type `[]`
348 Ref tuple(Sym sym); ///< Converts @p sym to a tuple of type '«n; I8»'.
349 ///@}
350
351 /// @name Pack
352 ///@{
354 Ref pack(Ref arity, Ref body);
355 Ref pack(Defs shape, Ref body);
356 Ref pack(u64 n, Ref body) { return pack(lit_nat(n), body); }
357 Ref pack(View<u64> shape, Ref body) {
358 return pack(DefVec(shape.size(), [&](auto i) { return lit_nat(shape[i]); }), body);
359 }
360 ///@}
361
362 /// @name Extract
363 /// @see core::extract_unsafe
364 ///@{
365 Ref extract(Ref d, Ref i);
366 Ref extract(Ref d, u64 a, u64 i) { return extract(d, lit_idx(a, i)); }
367 Ref extract(Ref d, u64 i) { return extract(d, d->as_lit_arity(), i); }
368
369 /// Builds `(f, t)#cond`.
370 /// @note Expects @p cond as first, @p t as second, and @p f as third argument.
371 Ref select(Ref cond, Ref t, Ref f) { return extract(tuple({f, t}), cond); }
372 ///@}
373
374 /// @name Insert
375 /// @see core::insert_unsafe
376 ///@{
377 Ref insert(Ref d, Ref i, Ref val);
378 Ref insert(Ref d, u64 a, u64 i, Ref val) { return insert(d, lit_idx(a, i), val); }
379 Ref insert(Ref d, u64 i, Ref val) { return insert(d, d->as_lit_arity(), i, val); }
380 ///@}
381
382 /// @name Lit
383 ///@{
384 const Lit* lit(Ref type, u64 val);
385 const Lit* lit_univ(u64 level) { return lit(univ(), level); }
386 const Lit* lit_univ_0() { return data_.lit_univ_0; }
387 const Lit* lit_univ_1() { return data_.lit_univ_1; }
388 const Lit* lit_nat(nat_t a) { return lit(type_nat(), a); }
389 const Lit* lit_nat_0() { return data_.lit_nat_0; }
390 const Lit* lit_nat_1() { return data_.lit_nat_1; }
391 const Lit* lit_nat_max() { return data_.lit_nat_max; }
392 const Lit* lit_0_1() { return data_.lit_0_1; }
393 // clang-format off
394 const Lit* lit_i1() { return lit_nat(Idx::bitwidth2size( 1)); };
395 const Lit* lit_i8() { return lit_nat(Idx::bitwidth2size( 8)); };
396 const Lit* lit_i16() { return lit_nat(Idx::bitwidth2size(16)); };
397 const Lit* lit_i32() { return lit_nat(Idx::bitwidth2size(32)); };
398 const Lit* lit_i64() { return lit_nat(Idx::bitwidth2size(64)); };
399 /// Constructs a Lit of type Idx of size @p size.
400 /// @note `size = 0` means `2^64`.
401 const Lit* lit_idx(nat_t size, u64 val) { return lit(type_idx(size), val); }
402
403 template<class I> const Lit* lit_idx(I val) {
404 static_assert(std::is_integral<I>());
405 return lit_idx(Idx::bitwidth2size(sizeof(I) * 8), val);
406 }
407
408 /// Constructs a Lit @p of type Idx of size $2^width$.
409 /// `val = 64` will be automatically converted to size `0` - the encoding for $2^64$.
410 const Lit* lit_int(nat_t width, u64 val) { return lit_idx(Idx::bitwidth2size(width), val); }
411 const Lit* lit_i1 (bool val) { return lit_int( 1, u64(val)); }
412 const Lit* lit_i2 (u8 val) { return lit_int( 2, u64(val)); }
413 const Lit* lit_i4 (u8 val) { return lit_int( 4, u64(val)); }
414 const Lit* lit_i8 (u8 val) { return lit_int( 8, u64(val)); }
415 const Lit* lit_i16(u16 val) { return lit_int(16, u64(val)); }
416 const Lit* lit_i32(u32 val) { return lit_int(32, u64(val)); }
417 const Lit* lit_i64(u64 val) { return lit_int(64, u64(val)); }
418 // clang-format on
419
420 /// Constructs a Lit of type Idx of size @p mod.
421 /// The value @p val will be adjusted modulo @p mod.
422 /// @note `mod == 0` is the special case for $2^64$ and no modulo will be performed on @p val.
423 const Lit* lit_idx_mod(nat_t mod, u64 val) { return lit_idx(mod, mod == 0 ? val : (val % mod)); }
424
425 const Lit* lit_bool(bool val) { return data_.lit_bool[size_t(val)]; }
426 const Lit* lit_ff() { return data_.lit_bool[0]; }
427 const Lit* lit_tt() { return data_.lit_bool[1]; }
428 // clang-format off
429 ///@}
430
431 /// @name Lattice
432 ///@{
433 template<bool Up>
434 Ref ext(Ref type);
436 Ref top(Ref type) { return ext<true>(type); }
437 Ref type_bot() { return data_.type_bot; }
438 Ref type_top() { return data_.type_top; }
439 Ref top_nat() { return data_.top_nat; }
440 template<bool Up> TBound<Up>* mut_bound(Ref type, size_t size) { return insert<TBound<Up>>(size, type, size); }
441 /// A *mut*able Bound of Type @p l%evel.
442 template<bool Up, level_t l = 0> TBound<Up>* mut_bound(size_t size) { return mut_bound<Up>(type<l>(), size); }
443 template<bool Up> Ref bound(Defs ops);
444 Join* mut_join(Ref type, size_t size) { return mut_bound<true>(type, size); }
445 Meet* mut_meet(Ref type, size_t size) { return mut_bound<false>(type, size); }
446 template<level_t l = 0> Join* mut_join(size_t size) { return mut_join(type<l>(), size); }
447 template<level_t l = 0> Meet* mut_meet(size_t size) { return mut_meet(type<l>(), size); }
448 Ref join(Defs ops) { return bound<true>(ops); }
449 Ref meet(Defs ops) { return bound<false>(ops); }
450 Ref ac(Ref type, Defs ops);
451 /// Infers the type using an *immutable* Meet.
452 Ref ac(Defs ops);
453 Ref vel(Ref type, Ref value);
454 Ref pick(Ref type, Ref value);
455 Ref test(Ref value, Ref probe, Ref match, Ref clash);
456 Ref singleton(Ref inner_type);
457 ///@}
458
459 /// @name Globals
460 /// @deprecated { will be removed }
461 ///@{
462 Global* global(Ref type, bool is_mutable = true) { return insert<Global>(1, type, is_mutable); }
463 ///@}
464 // clang-format on
465
466 /// @name Types
467 ///@{
468 const Nat* type_nat() { return data_.type_nat; }
469 const Idx* type_idx() { return data_.type_idx; }
470 /// @note `size = 0` means `2^64`.
471 Ref type_idx(Ref size) { return app(type_idx(), size); }
472 /// @note `size = 0` means `2^64`.
473 Ref type_idx(nat_t size) { return type_idx(lit_nat(size)); }
474
475 /// Constructs a type Idx of size $2^width$.
476 /// `width = 64` will be automatically converted to size `0` - the encoding for $2^64$.
478 // clang-format off
479 Ref type_bool() { return data_.type_bool; }
480 Ref type_i1() { return data_.type_bool; }
481 Ref type_i2() { return type_int( 2); };
482 Ref type_i4() { return type_int( 4); };
483 Ref type_i8() { return type_int( 8); };
484 Ref type_i16() { return type_int(16); };
485 Ref type_i32() { return type_int(32); };
486 Ref type_i64() { return type_int(64); };
487 // clang-format on
488 ///@}
489
490 /// @name Cope with implicit Arguments
491 ///@{
492 /// Places Infer arguments as demanded by Pi::implicit and then apps @p arg.
493 Ref iapp(Ref callee, Ref arg);
494 Ref iapp(Ref callee, Defs args) { return iapp(callee, tuple(args)); }
495 Ref iapp(Ref callee, nat_t arg) { return iapp(callee, lit_nat(arg)); }
496 template<class E>
497 Ref iapp(Ref callee, E arg) requires std::is_enum_v<E> && std::is_same_v<std::underlying_type_t<E>, nat_t>
498 {
499 return iapp(callee, lit_nat((nat_t)arg));
500 }
501
502 /// @name Vars & Muts
503 /// Manges sets of Vars and Muts.
504 ///@{
505 [[nodiscard]] Vars vars(const Var* var) { return move_.vars.singleton(var); }
506 [[nodiscard]] Muts muts(Def* mut) { return move_.muts.singleton(mut); }
507 [[nodiscard]] Vars merge(Vars a, Vars b) { return move_.vars.merge(a, b); }
508 [[nodiscard]] Muts merge(Muts a, Muts b) { return move_.muts.merge(a, b); }
509 [[nodiscard]] Vars insert(Vars vars, const Var* var) { return move_.vars.insert(vars, var); }
510 [[nodiscard]] Muts insert(Muts muts, Def* mut) { return move_.muts.insert(muts, mut); }
511 [[nodiscard]] Vars erase(Vars vars, const Var* var) { return move_.vars.erase(vars, var); }
512 [[nodiscard]] Muts erase(Muts muts, Def* mut) { return move_.muts.erase(muts, mut); }
513 [[nodiscard]] bool has_intersection(Vars v1, Vars v2) { return move_.vars.has_intersection(v1, v2); }
514 [[nodiscard]] bool has_intersection(Muts m1, Muts m2) { return move_.muts.has_intersection(m1, m2); }
515 ///@}
516
517 // clang-format off
518 template<class Id, class... Args> const Def* call(Id id, Args&&... args) { return call_(annex(id), std::forward<Args>(args)...); }
519 template<class Id, class... Args> const Def* call( Args&&... args) { return call_(annex<Id>(), std::forward<Args>(args)...); }
520 template<class T, class... Args> const Def* call_(Ref callee, T arg, Args&&... args) { return call_(iapp(callee, arg), std::forward<Args>(args)...); }
521 template<class T> const Def* call_(Ref callee, T arg) { return iapp(callee, arg); }
522 // clang-format on
523 ///@}
524
525 /// @name Helpers
526 ///@{
527 Ref iinfer(Ref def) { return Idx::size(def->type()); }
528 ///@}
529
530 /// @name dump/log
531 ///@{
532 Log& log();
533 void dummy() {}
534
535 void dump(std::ostream& os); ///< Dump to @p os.
536 void dump(); ///< Dump to `std::cout`.
537 void debug_dump(); ///< Dump in Debug build if World::log::level is Log::Level::Debug.
538 void write(const char* file); ///< Write to a file named @p file.
539 void write(); ///< Same above but file name defaults to World::name.
540 ///@}
541
542 /// @name dot
543 /// Dumps DOT to @p os.
544 ///@{
545 /// @param os Output stream
546 /// @param annexes If `true`, include all annexes - even if unused.
547 /// @param types Follow type dependencies?
548 void dot(std::ostream& os, bool annexes = false, bool types = false) const;
549 /// Same as above but write to @p file or `std::cout` if @p file is `nullptr`.
550 void dot(const char* file = nullptr, bool annexes = false, bool types = false) const;
551 ///@}
552
553private:
554 /// @name Put into Sea of Nodes
555 ///@{
556 template<class T, class... Args> const T* unify(size_t num_ops, Args&&... args) {
557 auto state = move_.arena.state();
558 auto def = allocate<T>(num_ops, std::forward<Args&&>(args)...);
559 if (auto loc = get_loc()) def->set(loc);
560 assert(!def->isa_mut());
561#ifdef MIM_ENABLE_CHECKS
562 if (flags().trace_gids) outln("{}: {} - {}", def->node_name(), def->gid(), def->flags());
563 if (flags().reeval_breakpoints && breakpoints().contains(def->gid())) fe::breakpoint();
564#endif
565 if (is_frozen()) {
566 --state_.pod.curr_gid;
567 auto i = move_.defs.find(def);
568 deallocate<T>(state, def);
569 if (i != move_.defs.end()) return static_cast<const T*>(*i);
570 return nullptr;
571 }
572
573 if (auto [i, ins] = move_.defs.emplace(def); !ins) {
574 deallocate<T>(state, def);
575 return static_cast<const T*>(*i);
576 }
577#ifdef MIM_ENABLE_CHECKS
578 if (!flags().reeval_breakpoints && breakpoints().contains(def->gid())) fe::breakpoint();
579#endif
580 def->finalize();
581 return def;
582 }
583
584 template<class T> void deallocate(fe::Arena::State state, const T* ptr) {
585 ptr->~T();
586 move_.arena.deallocate(state);
587 }
588
589 template<class T, class... Args> T* insert(size_t num_ops, Args&&... args) {
590 auto def = allocate<T>(num_ops, std::forward<Args&&>(args)...);
591 if (auto loc = get_loc()) def->set(loc);
592#ifdef MIM_ENABLE_CHECKS
593 if (flags().trace_gids) outln("{}: {} - {}", def->node_name(), def->gid(), def->flags());
594 if (breakpoints().contains(def->gid())) fe::breakpoint();
595#endif
596 assert_emplace(move_.defs, def);
597 return def;
598 }
599
600#if (!defined(_MSC_VER) && defined(NDEBUG))
601 struct Lock {
602 Lock() { assert((guard_ = !guard_) && "you are not allowed to recursively invoke allocate"); }
603 ~Lock() { guard_ = !guard_; }
604 static bool guard_;
605 };
606#else
607 struct Lock {
608 ~Lock() {}
609 };
610#endif
611
612 template<class T, class... Args> T* allocate(size_t num_ops, Args&&... args) {
613 static_assert(sizeof(Def) == sizeof(T),
614 "you are not allowed to introduce any additional data in subclasses of Def");
615 Lock lock;
616 move_.arena.align(alignof(T));
617 size_t num_bytes = sizeof(Def) + sizeof(uintptr_t) * num_ops;
618 auto ptr = move_.arena.allocate(num_bytes);
619 auto res = new (ptr) T(std::forward<Args&&>(args)...);
620 assert(res->num_ops() == num_ops);
621 return res;
622 }
623 ///@}
624
625 Driver* driver_;
626 State state_;
627
628 struct SeaHash {
629 size_t operator()(const Def* def) const { return def->hash(); }
630 };
631
632 struct SeaEq {
633 bool operator()(const Def* d1, const Def* d2) const { return d1->equal(d2); }
634 };
635
636 struct Move {
637 absl::btree_map<flags_t, const Def*> annexes;
638 absl::btree_map<Sym, Def*> externals;
639 fe::Arena arena;
640 absl::flat_hash_set<const Def*, SeaHash, SeaEq> defs;
641 Pool<const Var*> vars;
642 Pool<Def*> muts;
643 DefDefMap<DefVec> cache;
644
645 friend void swap(Move& m1, Move& m2) noexcept {
646 using std::swap;
647 // clang-format off
648 swap(m1.annexes, m2.annexes);
649 swap(m1.externals, m2.externals);
650 swap(m1.arena, m2.arena);
651 swap(m1.defs, m2.defs);
652 swap(m1.vars, m2.vars);
653 swap(m1.muts, m2.muts);
654 swap(m1.cache, m2.cache);
655 // clang-format on
656 }
657 } move_;
658
659 struct {
660 const Univ* univ;
661 const Type* type_0;
662 const Type* type_1;
663 const Bot* type_bot;
664 const Top* type_top;
665 const Def* type_bool;
666 const Top* top_nat;
667 const Sigma* sigma;
668 const Tuple* tuple;
669 const Nat* type_nat;
670 const Idx* type_idx;
671 const Def* table_id;
672 const Def* table_not;
673 const Lit* lit_univ_0;
674 const Lit* lit_univ_1;
675 const Lit* lit_nat_0;
676 const Lit* lit_nat_1;
677 const Lit* lit_nat_max;
678 const Lit* lit_0_1;
679 std::array<const Lit*, 2> lit_bool;
680 Lam* exit;
681 } data_;
682
683 friend void swap(World& w1, World& w2) noexcept {
684 using std::swap;
685 // clang-format off
686 swap(w1.state_, w2.state_);
687 swap(w1.data_, w2.data_ );
688 swap(w1.move_, w2.move_ );
689 // clang-format on
690
691 swap(w1.data_.univ->world_, w2.data_.univ->world_);
692 assert(&w1.univ()->world() == &w1);
693 assert(&w2.univ()->world() == &w2);
694 }
695
696 friend DefVec Def::reduce(const Def*);
697};
698
699} // namespace mim
A (possibly paramterized) Array.
Definition tuple.h:51
Base class for all Defs.
Definition def.h:220
DefVec reduce(const Def *arg) const
Rewrites Def::ops by substituting this mutable's Var with arg.
Definition def.cpp:208
bool is_external() const
Definition def.h:428
const Def * type() const
Definition def.h:245
Sym sym() const
Definition def.h:465
bool is_closed() const
Has no free_vars()?
Definition def.cpp:397
Some "global" variables needed all over the place.
Definition driver.h:17
A built-in constant of type .Nat -> *.
Definition def.h:731
static Ref size(Ref def)
Checks if def is a .Idx s and returns s or nullptr otherwise.
Definition def.cpp:558
static constexpr nat_t bitwidth2size(nat_t n)
Definition def.h:743
This node is a hole in the IR that is inferred by its context later on.
Definition check.h:12
A function.
Definition lam.h:96
std::variant< bool, const Def * > Filter
Definition lam.h:157
Facility to log what you are doing.
Definition log.h:17
A (possibly paramterized) Tuple.
Definition tuple.h:88
A dependent function type.
Definition lam.h:11
static Ref infer(Ref dom, Ref codom)
Definition check.cpp:266
Helper class to retrieve Infer::arg if present.
Definition def.h:85
A dependent tuple type.
Definition tuple.h:9
This is a thin wrapper for std::span<T, N> with the following additional features:
Definition span.h:28
Specific Bound depending on Up.
Definition lattice.h:31
Data constructor for a Sigma.
Definition tuple.h:40
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:33
const Lit * lit_idx(nat_t size, u64 val)
Constructs a Lit of type Idx of size size.
Definition world.h:401
const Lit * lit_idx(I val)
Definition world.h:403
const Lam * fun(Ref dom, Ref codom, Lam::Filter f, Ref body)
Definition world.h:292
Meet * mut_meet(Ref type, size_t size)
Definition world.h:445
bool has_intersection(Vars v1, Vars v2)
Definition world.h:513
Lam * mut_lam(Defs dom, Ref codom)
Definition world.h:299
Ref pack(View< u64 > shape, Ref body)
Definition world.h:357
const Pi * cn()
Definition world.h:267
Ref type_i64()
Definition world.h:486
Lam * mut_lam(Ref dom, Ref codom)
Definition world.h:298
friend void swap(World &w1, World &w2) noexcept
Definition world.h:683
Infer * mut_infer_type()
Definition world.h:224
const Lam * lam(Ref dom, Defs codom, Lam::Filter f, Ref body)
Definition world.h:290
Log & log()
Definition world.cpp:73
Ref type_i16()
Definition world.h:484
Infer * mut_infer(Ref type)
Definition world.h:222
Ref gid2def(u32 gid)
Lookup Def by gid.
Definition world.cpp:562
const Lit * lit_i8()
Definition world.h:395
Ref pack(u64 n, Ref body)
Definition world.h:356
Ref type_i2()
Definition world.h:481
World & operator=(World)=delete
const Lit * lit_i16(u16 val)
Definition world.h:415
Muts insert(Muts muts, Def *mut)
Definition world.h:510
Ref app(Ref callee, Defs args)
Definition world.h:313
Vars vars(const Var *var)
Definition world.h:505
const Lit * lit_i1(bool val)
Definition world.h:411
Global * global(Ref type, bool is_mutable=true)
Definition world.h:462
Ref arr(u64 n, Ref body)
Definition world.h:335
const Lit * lit_i32()
Definition world.h:397
Ref type_i1()
Definition world.h:480
Driver & driver()
Definition world.h:82
const Proxy * proxy(Ref type, Defs ops, u32 index, u32 tag)
Definition world.h:218
const Lam * con(Defs dom, Lam::Filter f, Ref body)
Definition world.h:287
Lam * mut_fun(Ref dom, Ref codom)
Definition world.h:302
const Def * call_(Ref callee, T arg, Args &&... args)
Definition world.h:520
Ref ext(Ref type)
Definition world.cpp:468
const Driver & driver() const
Definition world.h:81
const Lam * lam(Defs dom, Ref codom, Lam::Filter f, Ref body)
Definition world.h:289
const Axiom * axiom(Ref type)
See above.
Definition world.h:249
const Lit * lit_tt()
Definition world.h:427
World(Driver *)
Inherits the state into the new World.
Definition world.cpp:62
const Lam * fun(Defs dom, Ref codom, Lam::Filter f, Ref body)
Definition world.h:293
Lam * mut_con(Ref dom)
Definition world.h:296
void set(std::string_view name)
Definition world.h:86
Ref iapp(Ref callee, nat_t arg)
Definition world.h:495
Ref extract(Ref d, u64 i)
Definition world.h:367
u32 curr_gid() const
Manage global identifier - a unique number for each Def.
Definition world.h:89
Lam * exit()
Used as a dummy exit node within Scope.
Definition world.h:307
const auto & annexes() const
Definition world.h:167
World inherit()
Definition world.h:73
Ref iapp(Ref callee, Ref arg)
Definition world.cpp:166
const Lam * lam(Defs dom, Defs codom, Lam::Filter f, Ref body)
Definition world.h:291
Muts merge(Muts a, Muts b)
Definition world.h:508
const Pi * fn(Ref dom, Ref codom, bool implicit=false)
Definition world.h:270
Infer * mut_infer_univ()
Definition world.h:223
const Univ * univ()
Definition world.h:204
Ref test(Ref value, Ref probe, Ref match, Ref clash)
Definition world.cpp:518
Ref type_bool()
Definition world.h:479
const Def * call_(Ref callee, T arg)
Definition world.h:521
const Lit * lit_0_1()
Definition world.h:392
Ref iinfer(Ref def)
Definition world.h:527
const Pi * pi(Defs dom, Ref codom, bool implicit=false)
Definition world.h:256
const Pi * pi(Ref dom, Defs codom, bool implicit=false)
Definition world.h:257
World & verify()
Verifies that all externals() and annexes() are Def::is_closed(), if MIM_ENABLE_CHECKS.
Definition world.cpp:568
const Lam * fun(Defs dom, Defs codom, Lam::Filter f, Ref body)
Definition world.h:295
const Lit * lit_i64()
Definition world.h:398
const Lit * lit_idx_mod(nat_t mod, u64 val)
Constructs a Lit of type Idx of size mod.
Definition world.h:423
const Idx * type_idx()
Definition world.h:469
Ref umax(Defs)
Definition world.cpp:111
Pi * mut_pi(Ref type, bool implicit=false)
Definition world.h:259
const Lit * lit_univ_0()
Definition world.h:386
const Def * annex(Id id)
Lookup annex by Axiom::id.
Definition world.h:185
const Pi * cn(Ref dom, bool implicit=false)
Definition world.h:268
void set_loc(Loc loc={})
Definition world.h:110
Sym name() const
Definition world.h:84
Join * mut_join(Ref type, size_t size)
Definition world.h:444
Ref insert(Ref d, u64 i, Ref val)
Definition world.h:379
Ref iapp(Ref callee, E arg)
Definition world.h:497
const Pi * cn(Defs dom, bool implicit=false)
Definition world.h:269
void dump()
Dump to std::cout.
Definition dump.cpp:487
void make_internal(Def *def)
Definition world.h:175
Arr * mut_arr(Ref type)
Definition world.h:331
const Lit * lit_univ_1()
Definition world.h:387
void write()
Same above but file name defaults to World::name.
Definition dump.cpp:498
Ref bot(Ref type)
Definition world.h:435
const Def * register_annex(plugin_t p, tag_t t, sub_t s, const Def *def)
Definition world.h:197
const auto & externals() const
Definition world.h:168
Ref insert(Ref d, Ref i, Ref val)
Definition world.cpp:353
const Lit * lit_i1()
Definition world.h:394
const Nat * type_nat()
Definition world.h:468
Sigma * mut_sigma(Ref type, size_t size)
Definition world.h:322
Ref var(Ref type, Def *mut)
Definition world.cpp:157
Ref arr(Ref shape, Ref body)
Definition world.cpp:395
const Pi * fn(Ref dom, Defs codom, bool implicit=false)
Definition world.h:272
Lam * mut_lam(Ref dom, Defs codom)
Definition world.h:300
Ref meet(Defs ops)
Definition world.h:449
Flags & flags()
Retrive compile Flags.
Definition world.cpp:74
ScopedLoc push(Loc loc)
Definition world.h:111
void debug_dump()
Dump in Debug build if World::log::level is Log::Level::Debug.
Definition dump.cpp:489
u32 next_gid()
Definition world.h:90
Lam * mut_fun(Ref dom, Defs codom)
Definition world.h:304
Ref type_idx(Ref size)
Definition world.h:471
Muts erase(Muts muts, Def *mut)
Definition world.h:512
const auto & breakpoints()
Definition world.h:154
const Type * type()
Definition world.h:209
void set(Sym name)
Definition world.h:85
Ref type_int(nat_t width)
Constructs a type Idx of size $2^width$.
Definition world.h:477
Lam * mut_fun(Defs dom, Defs codom)
Definition world.h:305
const Lit * lit_i2(u8 val)
Definition world.h:412
Ref app(Ref callee, Ref arg)
Definition world.cpp:187
Vars merge(Vars a, Vars b)
Definition world.h:507
bool is_frozen() const
Definition world.h:130
Loc get_loc() const
Definition world.h:109
const Lit * lit_nat_0()
Definition world.h:389
Ref ac(Ref type, Defs ops)
Definition world.cpp:499
Sym sym(std::string_view)
Definition world.cpp:77
const Pi * pi(Ref dom, Ref codom, bool implicit=false)
Definition world.h:255
Infer * mut_infer_entity()
Either a value ?:?:.Type ? or a type ?:.Type ?:.Type ?.
Definition world.h:227
const Lit * lit_i16()
Definition world.h:396
const Lit * lit_ff()
Definition world.h:426
const Lit * lit_nat_max()
Definition world.h:391
Ref raw_app(Ref type, Ref callee, Defs args)
Definition world.h:315
Def * external(Sym name)
Lookup by name.
Definition world.h:182
const Def * call(Id id, Args &&... args)
Definition world.h:518
Ref select(Ref cond, Ref t, Ref f)
Builds (f, t)#cond.
Definition world.h:371
Ref type_idx(nat_t size)
Definition world.h:473
Vars insert(Vars vars, const Var *var)
Definition world.h:509
TBound< Up > * mut_bound(Ref type, size_t size)
Definition world.h:440
Sym append_suffix(Sym name, std::string suffix)
Appends a suffix or an increasing number if the suffix already exists.
Definition world.cpp:534
Ref type_i32()
Definition world.h:485
Join * mut_join(size_t size)
Definition world.h:446
Ref arr_unsafe(Ref body)
Definition world.h:339
const Lam * fun(Ref dom, Defs codom, Lam::Filter f, Ref body)
Definition world.h:294
const Lit * lit_i32(u32 val)
Definition world.h:416
const Lit * lit_i8(u8 val)
Definition world.h:414
Ref pack(Ref arity, Ref body)
Definition world.cpp:422
Ref arr(View< u64 > shape, Ref body)
Definition world.h:336
Ref insert(Ref d, u64 a, u64 i, Ref val)
Definition world.h:378
Lam * mut_lam(Defs dom, Defs codom)
Definition world.h:301
Sigma * mut_sigma(size_t size)
A *mut*able Sigma of type level.
Definition world.h:324
const Lit * lit_univ(u64 level)
Definition world.h:385
Ref pick(Ref type, Ref value)
Definition world.cpp:516
const Pi * pi(Defs dom, Defs codom, bool implicit=false)
Definition world.h:258
Ref bound(Defs ops)
Definition world.cpp:475
const Tuple * tuple()
the unit value of type []
Definition world.h:347
const Type * type_infer_univ()
Definition world.h:208
Ref iapp(Ref callee, Defs args)
Definition world.h:494
void make_external(Def *def)
Definition world.h:169
void dummy()
Definition world.h:533
Ref type_i8()
Definition world.h:483
Muts muts(Def *mut)
Definition world.h:506
Ref extract(Ref d, Ref i)
Definition world.cpp:291
Lam * mut_fun(Defs dom, Ref codom)
Definition world.h:303
Ref type_top()
Definition world.h:438
const Lit * lit_i64(u64 val)
Definition world.h:417
Ref filter(Lam::Filter filter)
Definition world.h:279
const Lit * lit(Ref type, u64 val)
Definition world.cpp:452
Ref vel(Ref type, Ref value)
Definition world.cpp:511
const Sigma * sigma()
The unit type within Type 0.
Definition world.h:326
const Lit * lit_nat(nat_t a)
Definition world.h:388
const State & state() const
Definition world.h:79
Ref top_nat()
Definition world.h:439
Ref extract(Ref d, u64 a, u64 i)
Definition world.h:366
TBound< Up > * mut_bound(size_t size)
A *mut*able Bound of Type level.
Definition world.h:442
const Axiom * axiom(NormalizeFn n, u8 curry, u8 trip, Ref type, plugin_t p, tag_t t, sub_t s)
Definition world.h:237
const Def * register_annex(flags_t f, const Def *)
Definition world.cpp:80
Ref join(Defs ops)
Definition world.h:448
Ref type_i4()
Definition world.h:482
const Pi * fn(Defs dom, Ref codom, bool implicit=false)
Definition world.h:271
Arr * mut_arr()
Definition world.h:332
const Axiom * axiom(NormalizeFn n, u8 curry, u8 trip, Ref type)
Builds a fresh Axiom with descending Axiom::sub.
Definition world.h:246
const Lit * lit_int(nat_t width, u64 val)
Constructs a Lit of type Idx of size $2^width$.
Definition world.h:410
Ref raw_app(Ref type, Ref callee, Ref arg)
Definition world.cpp:218
const Lit * lit_bool(bool val)
Definition world.h:425
void breakpoint(u32 gid)
Trigger breakpoint in your debugger when creating Def with Def::gid gid.
Definition world.cpp:560
const Lam * lam(Ref dom, Ref codom, Lam::Filter f, Ref body)
Definition world.h:288
Ref uinc(Ref op, level_t offset=1)
Definition world.cpp:102
Meet * mut_meet(size_t size)
Definition world.h:447
Lam * mut_con(Defs dom)
Definition world.h:297
Vars erase(Vars vars, const Var *var)
Definition world.h:511
const Def * call(Args &&... args)
Definition world.h:519
const Axiom * axiom(Ref type, plugin_t p, tag_t t, sub_t s)
Definition world.h:240
Ref singleton(Ref inner_type)
Definition world.cpp:532
World(World &&other) noexcept
Definition world.h:69
const Lit * lit_nat_1()
Definition world.h:390
bool freeze(bool on=true) const
Yields old frozen state.
Definition world.h:133
Pack * mut_pack(Ref type)
Definition world.h:353
const Lit * lit_i4(u8 val)
Definition world.h:413
Ref top(Ref type)
Definition world.h:436
void dot(std::ostream &os, bool annexes=false, bool types=false) const
Definition dot.cpp:140
const Lam * lam(const Pi *pi, Lam::Filter f, Ref body)
Definition world.h:283
const Lam * con(Ref dom, Lam::Filter f, Ref body)
Definition world.h:286
const Pi * fn(Defs dom, Defs codom, bool implicit=false)
Definition world.h:273
bool has_intersection(Muts m1, Muts m2)
Definition world.h:514
Ref type_bot()
Definition world.h:437
Lam * mut_lam(const Pi *pi)
Definition world.h:284
const Def * annex()
Get Axiom from a plugin.
Definition world.h:194
@ Sigma
Definition def.h:39
@ Tuple
Definition def.h:39
@ Nat
Definition def.h:39
@ Idx
Definition def.h:39
@ Lam
Definition def.h:39
@ Lit
Definition def.h:39
Definition cfg.h:11
u64 nat_t
Definition types.h:43
Vector< const Def * > DefVec
Definition def.h:61
absl::flat_hash_map< DefDef, To, DefDefHash, DefDefEq > DefDefMap
Definition def.h:630
u8 sub_t
Definition types.h:48
auto assert_emplace(C &container, Args &&... args)
Invokes emplace on container, asserts that insertion actually happened, and returns the iterator.
Definition util.h:102
u64 flags_t
Definition types.h:45
auto lookup(const C &container, const K &key)
Yields pointer to element (or the element itself if it is already a pointer), if found and nullptr ot...
Definition util.h:93
auto match(Ref def)
Definition axiom.h:105
void error(Loc loc, const char *f, Args &&... args)
Definition dbg.h:122
u64 level_t
Definition types.h:42
TExt< true > Top
Definition lattice.h:152
std::ostream & outln(const char *fmt, Args &&... args)
Definition print.h:189
u64 plugin_t
Definition types.h:46
uint32_t u32
Definition types.h:34
TExt< false > Bot
Definition lattice.h:151
uint64_t u64
Definition types.h:34
u8 tag_t
Definition types.h:47
uint8_t u8
Definition types.h:34
Ref(*)(Ref, Ref, Ref) NormalizeFn
Definition def.h:101
uint16_t u16
Definition types.h:34
Compiler switches that must be saved and looked up in later phases of compilation.
Definition flags.h:11
constexpr decltype(auto) get(mim::Span< T, N > span)
Definition span.h:113
static constexpr plugin_t Global_Plugin
Definition plugin.h:58
static Sym demangle(Driver &, plugin_t plugin)
Reverts an Axiom::mangled string to a Sym.
Definition plugin.cpp:37
static constexpr flags_t Base
Definition plugin.h:118
Use to World::freeze and automatically unfreeze at the end of scope.
Definition world.h:140
Freezer(const World &world)
Definition world.h:141
const World & world
Definition world.h:146
ScopedLoc(World &world, Loc old_loc)
Definition world.h:99
friend void swap(State &s1, State &s2) noexcept
Definition world.h:52
struct mim::World::State::POD pod
absl::flat_hash_set< uint32_t > breakpoints
Definition world.h:50
Plain Old Data
Definition world.h:41