Merge commit '12fdc07' into lang/foundations
This commit is contained in:
commit
30a641d249
8 changed files with 57983 additions and 57067 deletions
|
|
@ -1103,6 +1103,8 @@ function emit_expr_raw(e: Node) -> Val {
|
|||
if is_fp(g.ty) { return val(to_fp(cv, g.ty, `const {e.s}`), g.ty) }
|
||||
return cv
|
||||
}
|
||||
let lz = lazy_state_read(g, e.s) # a state: made on first read (emit_lazy.ludic)
|
||||
if lz != null { return val(lz, g.ty) }
|
||||
let r = emit_bind(`load {llty(g.ty)}, ptr @g_{e.s}`)
|
||||
return val(r, g.ty)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ function emit_inj_thunk(d: Node) -> pointer {
|
|||
while i < len(d.kids) {
|
||||
let p = d.kids[i]
|
||||
if i < k {
|
||||
body = body + ` %s{itoa(i)} = load ptr, ptr @g_state${p.ty}\n`
|
||||
if is_lazy_state(find_global(state_global(p.ty))) { body = body + ` %s{itoa(i)} = call ptr @S_state${p.ty}()\n` } else { body = body + ` %s{itoa(i)} = load ptr, ptr @g_state${p.ty}\n` }
|
||||
if len(args) > 0 { args = args + ", " }
|
||||
args = args + `ptr %s{itoa(i)}`
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ function global_needs_init_code(d: Node) -> bool {
|
|||
function emit_global_init_fn() -> void {
|
||||
emit_init_fn("L_init_runtime", true)
|
||||
emit_init_fn("L_init_globals", false)
|
||||
emit_state_getters()
|
||||
}
|
||||
# 0.S: the runtime's states are made first, before it boots (rt_init reads them); the rest after
|
||||
function is_runtime_state_var(d: Node) -> bool { return d.uns == 1 and is_state_ty(d.ty) and is_runtime_file(d.file) }
|
||||
|
|
@ -85,7 +86,7 @@ function emit_init_fn(name: pointer, runtime: bool) -> void {
|
|||
let i = order[oi]
|
||||
oi += 1
|
||||
let d = prog[i]
|
||||
if d.kind == N_VAR and global_needs_init_code(d) and is_runtime_state_var(d) == runtime {
|
||||
if d.kind == N_VAR and global_needs_init_code(d) and is_runtime_state_var(d) == runtime and not is_lazy_state(d) {
|
||||
# an initializer is the global's own file's code: its errors, and what its module
|
||||
# may see (L3), are that file's - not whichever statement was lowered last
|
||||
g_err_file = d.file
|
||||
|
|
|
|||
50
selfhost/backend/emit_lazy.ludic
Normal file
50
selfhost/backend/emit_lazy.ludic
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# emit_lazy.ludic - a program's state made when it is first injected, not before Boot: a process that
|
||||
# takes a short path through the program (the launcher's watcher, which only spawns and waits) never
|
||||
# makes the states it does not touch - the camera's frame buffers, the town's tables, the pools.
|
||||
# @S_<global>() is the getter every read of a state global calls: made on first call, by its own
|
||||
# initializer, after every registry and plain global (L_init_globals) - so a default may read them.
|
||||
# What it makes is declared (@lp_fdecl): a state first touched in play is made once, not kept per frame.
|
||||
function is_lazy_state(d: Node) -> bool {
|
||||
if d == null or d.kind != N_VAR or d.uns != 1 or d.a == null { return false }
|
||||
return str_prefix(d.s, "state$") and is_state_ty(d.ty) and not is_runtime_file(d.file)
|
||||
}
|
||||
|
||||
function emit_state_getters() -> void {
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
if is_lazy_state(prog[i]) { emit_state_getter(prog[i]) }
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
function emit_state_getter(d: Node) -> void {
|
||||
let name = `S_{d.s}`
|
||||
fence_enter(name)
|
||||
ll_t = 0; ll_lbl = 0; g_term = false; loc_reset(); nloop = 0; nself = 0
|
||||
ret_ty = "ptr"
|
||||
let fbody = buf_new()
|
||||
falloc = buf_new()
|
||||
let saved = code
|
||||
code = fbody
|
||||
g_err_file = d.file
|
||||
g_err_line = d.line
|
||||
emit(` %p0 = load ptr, ptr @g_{d.s}\n %z0 = icmp eq ptr %p0, null\n br i1 %z0, label %make, label %have\nhave:\n ret ptr %p0\nmake:\n`)
|
||||
emit(" %decl.in = atomicrmw add ptr @lp_fdecl, i32 1 monotonic\n")
|
||||
let v = emit_expr(d.a)
|
||||
let cv = coerce_code(v, d.ty)
|
||||
emit(` store ptr {cv}, ptr @g_{d.s}\n`)
|
||||
emit(" %decl.out = atomicrmw sub ptr @lp_fdecl, i32 1 monotonic\n")
|
||||
emit(` ret ptr {cv}\n`)
|
||||
code = saved
|
||||
emit(`define ptr @{name}() {{\nentry:\n`)
|
||||
emit(buf_str(falloc))
|
||||
emit(" br label %start\nstart:\n")
|
||||
emit(buf_str(fbody))
|
||||
emit("}\n\n")
|
||||
}
|
||||
|
||||
# a read of a state global: its getter's answer, or null when it is not lazy
|
||||
function lazy_state_read(g: Node, s: pointer) -> pointer {
|
||||
if not is_lazy_state(g) { return null }
|
||||
return emit_bind(`call ptr @S_{s}()`)
|
||||
}
|
||||
|
|
@ -4,6 +4,9 @@
|
|||
# parts of compiler/back/ir_decl.c.
|
||||
|
||||
const MAX_ENT: int = 1024
|
||||
# the stores' first size, doubled as entities come: one slot per property type is made for every
|
||||
# program at start, so 1024 of them made ~1,500 stores 48 MB in a process that spawns nothing
|
||||
const ECS_FIRST: int = 8
|
||||
|
||||
function has_systems() -> bool {
|
||||
var i = 0
|
||||
|
|
@ -171,7 +174,7 @@ function ecs_base(store: pointer) -> pointer {
|
|||
function emit_ecs_grow() -> void {
|
||||
emit("define void @L_grow(i32 %need) {\nentry:\n %cap = load i32, ptr @L_cap\n")
|
||||
emit(" %ok = icmp sle i32 %need, %cap\n br i1 %ok, label %done, label %grow\ngrow:\n")
|
||||
emit(` %c0 = icmp eq i32 %cap, 0\n %start = select i1 %c0, i32 {itoa(MAX_ENT)}, i32 %cap\n br label %dbl\n`)
|
||||
emit(` %c0 = icmp eq i32 %cap, 0\n %start = select i1 %c0, i32 {itoa(ECS_FIRST)}, i32 %cap\n br label %dbl\n`)
|
||||
emit("dbl:\n %nc = phi i32 [ %start, %grow ], [ %nc2, %dbl2 ]\n %enough = icmp sge i32 %nc, %need\n")
|
||||
emit(" br i1 %enough, label %apply, label %dbl2\ndbl2:\n %nc2 = mul i32 %nc, 2\n br label %dbl\n")
|
||||
emit("apply:\n %cap64 = sext i32 %cap to i64\n %nc64 = sext i32 %nc to i64\n")
|
||||
|
|
|
|||
56369
selfhost/ludicc.seed.ll
56369
selfhost/ludicc.seed.ll
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -49,6 +49,7 @@ function selfhost_frags() -> []pointer {
|
|||
push(f, "selfhost/backend/emit_escape.ludic")
|
||||
push(f, "selfhost/backend/emit_resource.ludic")
|
||||
push(f, "selfhost/backend/emit_head.ludic")
|
||||
push(f, "selfhost/backend/emit_lazy.ludic")
|
||||
push(f, "selfhost/backend/emit_deps.ludic")
|
||||
push(f, "selfhost/backend/emit_addr.ludic")
|
||||
push(f, "selfhost/backend/emit_intrin.ludic")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue