inline intrinsics

This commit is contained in:
2026-02-21 19:23:53 -06:00
parent 6d6b53009f
commit 017b63ba80
3 changed files with 487 additions and 112 deletions

367
mcode.cm
View File

@@ -879,6 +879,77 @@ var mcode = function(ast) {
var inline_some = true
var inline_reduce = true
var inline_map = true
var inline_find = true
// --- Helper: emit arity-dispatched callback invocation ---
// ctx = {fn, fn_arity, result, null_s, frame, zero, one, az, ao, prefix}
// args = [slot_for_arg1, slot_for_arg2] — data args (not this)
// max_args = 1 or 2 — how many data args to support
var emit_arity_call = function(ctx, args, max_args) {
var call_one = gen_label(ctx.prefix + "_c1")
var call_two = gen_label(ctx.prefix + "_c2")
var call_done = gen_label(ctx.prefix + "_cd")
emit_3("eq", ctx.az, ctx.fn_arity, ctx.zero)
emit_jump_cond("jump_false", ctx.az, call_one)
emit_3("frame", ctx.frame, ctx.fn, 0)
emit_3("setarg", ctx.frame, 0, ctx.null_s)
emit_2("invoke", ctx.frame, ctx.result)
emit_jump(call_done)
emit_label(call_one)
if (max_args >= 2) {
emit_3("eq", ctx.ao, ctx.fn_arity, ctx.one)
emit_jump_cond("jump_false", ctx.ao, call_two)
}
emit_3("frame", ctx.frame, ctx.fn, 1)
emit_3("setarg", ctx.frame, 0, ctx.null_s)
emit_3("setarg", ctx.frame, 1, args[0])
emit_2("invoke", ctx.frame, ctx.result)
if (max_args < 2) {
emit_label(call_done)
return null
}
emit_jump(call_done)
emit_label(call_two)
emit_3("frame", ctx.frame, ctx.fn, 2)
emit_3("setarg", ctx.frame, 0, ctx.null_s)
emit_3("setarg", ctx.frame, 1, args[0])
emit_3("setarg", ctx.frame, 2, args[1])
emit_2("invoke", ctx.frame, ctx.result)
emit_label(call_done)
return null
}
// --- Helper: forward loop scaffolding ---
// L = {arr, len, i, check, item, one, loop_label, done_label}
// body_fn(L) — called between element load and increment
var emit_forward_loop = function(L, body_fn) {
emit_2("int", L.i, 0)
emit_label(L.loop_label)
emit_3("lt", L.check, L.i, L.len)
emit_jump_cond("jump_false", L.check, L.done_label)
emit_3("load_index", L.item, L.arr, L.i)
body_fn(L)
emit_3("add", L.i, L.i, L.one)
emit_jump(L.loop_label)
emit_label(L.done_label)
return null
}
// --- Helper: reverse loop scaffolding ---
var emit_reverse_loop = function(L, body_fn) {
var zero = alloc_slot()
emit_2("int", zero, 0)
emit_3("subtract", L.i, L.len, L.one)
emit_label(L.loop_label)
emit_3("ge", L.check, L.i, zero)
emit_jump_cond("jump_false", L.check, L.done_label)
emit_3("load_index", L.item, L.arr, L.i)
body_fn(L)
emit_3("subtract", L.i, L.i, L.one)
emit_jump(L.loop_label)
emit_label(L.done_label)
return null
}
// --- Helper: emit a reduce loop body ---
// r = {acc, i, arr, fn, len, fn_arity}; emits loop updating acc in-place.
@@ -895,13 +966,12 @@ var mcode = function(ast) {
var null_s = alloc_slot()
var one = alloc_slot()
var zero = alloc_slot()
var arity_is_zero = alloc_slot()
var arity_is_one = alloc_slot()
var az = alloc_slot()
var ao = alloc_slot()
var f = alloc_slot()
var loop_label = gen_label("reduce_loop")
var call_one_label = gen_label("reduce_call_one")
var call_two_label = gen_label("reduce_call_two")
var call_done_label = gen_label("reduce_call_done")
var ctx = {fn: fn_slot, fn_arity: fn_arity, result: acc, null_s: null_s,
frame: f, zero: zero, one: one, az: az, ao: ao, prefix: "reduce"}
emit_2("int", one, 1)
emit_2("int", zero, 0)
emit_1("null", null_s)
@@ -913,27 +983,7 @@ var mcode = function(ast) {
}
emit_jump_cond("jump_false", check, done_label)
emit_3("load_index", item, arr_slot, i)
emit_3("eq", arity_is_zero, fn_arity, zero)
emit_jump_cond("jump_false", arity_is_zero, call_one_label)
emit_3("frame", f, fn_slot, 0)
emit_3("setarg", f, 0, null_s)
emit_2("invoke", f, acc)
emit_jump(call_done_label)
emit_label(call_one_label)
emit_3("eq", arity_is_one, fn_arity, one)
emit_jump_cond("jump_false", arity_is_one, call_two_label)
emit_3("frame", f, fn_slot, 1)
emit_3("setarg", f, 0, null_s)
emit_3("setarg", f, 1, acc)
emit_2("invoke", f, acc)
emit_jump(call_done_label)
emit_label(call_two_label)
emit_3("frame", f, fn_slot, 2)
emit_3("setarg", f, 0, null_s)
emit_3("setarg", f, 1, acc)
emit_3("setarg", f, 2, item)
emit_2("invoke", f, acc)
emit_label(call_done_label)
emit_arity_call(ctx, [acc, item], 2)
if (forward) {
emit_3("add", i, i, one)
} else {
@@ -942,60 +992,63 @@ var mcode = function(ast) {
emit_jump(loop_label)
}
// --- Inline expansion: arrfor(arr, fn) ---
var expand_inline_arrfor = function(dest, arr_slot, fn_slot) {
// --- Inline expansion: arrfor(arr, fn[, rev[, exit]]) ---
var expand_inline_arrfor = function(dest, args, nargs) {
var arr_slot = args.arr
var fn_slot = args.fn
var len = alloc_slot()
var i = alloc_slot()
var check = alloc_slot()
var item = alloc_slot()
var fn_arity = alloc_slot()
var arity_is_zero = alloc_slot()
var arity_is_one = alloc_slot()
var az = alloc_slot()
var ao = alloc_slot()
var null_s = alloc_slot()
var zero = alloc_slot()
var one = alloc_slot()
var f = alloc_slot()
var discard = alloc_slot()
var loop_label = gen_label("arrfor_loop")
var done_label = gen_label("arrfor_done")
var call_one_label = gen_label("arrfor_call_one")
var call_two_label = gen_label("arrfor_call_two")
var call_done_label = gen_label("arrfor_call_done")
var val = alloc_slot()
var eq_check = alloc_slot()
var early_exit = gen_label("arrfor_exit")
var done_final = gen_label("arrfor_final")
var rev_label = gen_label("arrfor_rev")
var final_label = gen_label("arrfor_fwd_done")
var fwd_L = {arr: arr_slot, len: len, i: i, check: check, item: item, one: one,
loop_label: gen_label("arrfor_fwd"), done_label: gen_label("arrfor_fwd_d")}
var rev_L = {arr: arr_slot, len: len, i: i, check: check, item: item, one: one,
loop_label: gen_label("arrfor_rev_l"), done_label: gen_label("arrfor_rev_d")}
var ctx = {fn: fn_slot, fn_arity: fn_arity, result: val, null_s: null_s,
frame: f, zero: zero, one: one, az: az, ao: ao, prefix: "arrfor"}
var body_fn = function(L) {
emit_arity_call(ctx, [L.item, L.i], 2)
if (nargs >= 4 && args.exit >= 0) {
emit_3("eq", eq_check, val, args.exit)
emit_jump_cond("jump_true", eq_check, early_exit)
}
return null
}
emit_2("length", len, arr_slot)
emit_2("int", i, 0)
emit_2("int", zero, 0)
emit_2("int", one, 1)
emit_1("null", null_s)
emit_2("length", fn_arity, fn_slot)
emit_label(loop_label)
emit_3("lt", check, i, len)
emit_jump_cond("jump_false", check, done_label)
emit_3("load_index", item, arr_slot, i)
emit_3("eq", arity_is_zero, fn_arity, zero)
emit_jump_cond("jump_false", arity_is_zero, call_one_label)
emit_3("frame", f, fn_slot, 0)
emit_3("setarg", f, 0, null_s)
emit_2("invoke", f, discard)
emit_jump(call_done_label)
emit_label(call_one_label)
emit_3("eq", arity_is_one, fn_arity, one)
emit_jump_cond("jump_false", arity_is_one, call_two_label)
emit_3("frame", f, fn_slot, 1)
emit_3("setarg", f, 0, null_s)
emit_3("setarg", f, 1, item)
emit_2("invoke", f, discard)
emit_jump(call_done_label)
emit_label(call_two_label)
emit_3("frame", f, fn_slot, 2)
emit_3("setarg", f, 0, null_s)
emit_3("setarg", f, 1, item)
emit_3("setarg", f, 2, i)
emit_2("invoke", f, discard)
emit_label(call_done_label)
emit_3("add", i, i, one)
emit_jump(loop_label)
emit_label(done_label)
if (nargs <= 2) {
emit_forward_loop(fwd_L, body_fn)
} else {
emit_jump_cond("jump_true", args.rev, rev_label)
emit_forward_loop(fwd_L, body_fn)
emit_jump(final_label)
emit_label(rev_label)
emit_reverse_loop(rev_L, body_fn)
emit_label(final_label)
}
emit_1("null", dest)
emit_jump(done_final)
if (nargs >= 4 && args.exit >= 0) {
emit_label(early_exit)
emit_2("move", dest, val)
}
emit_label(done_final)
return dest
}
@@ -1113,61 +1166,151 @@ var mcode = function(ast) {
var check = alloc_slot()
var item = alloc_slot()
var fn_arity = alloc_slot()
var arity_is_zero = alloc_slot()
var arity_is_one = alloc_slot()
var az = alloc_slot()
var ao = alloc_slot()
var null_s = alloc_slot()
var zero = alloc_slot()
var one = alloc_slot()
var f = alloc_slot()
var val = alloc_slot()
var loop_label = gen_label("filter_loop")
var call_one_label = gen_label("filter_call_one")
var call_two_label = gen_label("filter_call_two")
var call_done_label = gen_label("filter_call_done")
var skip_label = gen_label("filter_skip")
var done_label = gen_label("filter_done")
var skip = gen_label("filter_skip")
var ctx = {fn: fn_slot, fn_arity: fn_arity, result: val, null_s: null_s,
frame: f, zero: zero, one: one, az: az, ao: ao, prefix: "filter"}
var L = {arr: arr_slot, len: len, i: i, check: check, item: item, one: one,
loop_label: gen_label("filter_loop"), done_label: gen_label("filter_done")}
add_instr(["array", result, 0])
emit_2("length", len, arr_slot)
emit_2("int", i, 0)
emit_2("int", zero, 0)
emit_2("int", one, 1)
emit_1("null", null_s)
emit_2("length", fn_arity, fn_slot)
emit_label(loop_label)
emit_3("lt", check, i, len)
emit_jump_cond("jump_false", check, done_label)
emit_3("load_index", item, arr_slot, i)
emit_3("eq", arity_is_zero, fn_arity, zero)
emit_jump_cond("jump_false", arity_is_zero, call_one_label)
emit_3("frame", f, fn_slot, 0)
emit_3("setarg", f, 0, null_s)
emit_2("invoke", f, val)
emit_jump(call_done_label)
emit_label(call_one_label)
emit_3("eq", arity_is_one, fn_arity, one)
emit_jump_cond("jump_false", arity_is_one, call_two_label)
emit_3("frame", f, fn_slot, 1)
emit_3("setarg", f, 0, null_s)
emit_3("setarg", f, 1, item)
emit_2("invoke", f, val)
emit_jump(call_done_label)
emit_label(call_two_label)
emit_3("frame", f, fn_slot, 2)
emit_3("setarg", f, 0, null_s)
emit_3("setarg", f, 1, item)
emit_3("setarg", f, 2, i)
emit_2("invoke", f, val)
emit_label(call_done_label)
emit_jump_cond("jump_false", val, skip_label)
emit_2("push", result, item)
emit_label(skip_label)
emit_3("add", i, i, one)
emit_jump(loop_label)
emit_label(done_label)
emit_forward_loop(L, function(L) {
emit_arity_call(ctx, [L.item, L.i], 2)
emit_jump_cond("jump_false", val, skip)
emit_2("push", result, L.item)
emit_label(skip)
return null
})
emit_2("move", dest, result)
return dest
}
// --- Inline expansion: find(arr, target[, rev[, from]]) ---
var expand_inline_find = function(dest, args, nargs) {
var arr_slot = args.arr
var target = args.target
var len = alloc_slot()
var i = alloc_slot()
var check = alloc_slot()
var item = alloc_slot()
var fn_arity = alloc_slot()
var az = alloc_slot()
var ao = alloc_slot()
var null_s = alloc_slot()
var zero = alloc_slot()
var one = alloc_slot()
var f = alloc_slot()
var val = alloc_slot()
var is_fn = alloc_slot()
var eq_check = alloc_slot()
var fn_mode_label = gen_label("find_fn")
var found_label = gen_label("find_found")
var not_found_label = gen_label("find_nf")
var final_label = gen_label("find_final")
var vrev = gen_label("find_vrev")
var vdone = gen_label("find_vdone")
var frev = gen_label("find_frev")
var fdone = gen_label("find_fdone")
var vL = {arr: arr_slot, len: len, i: i, check: check, item: item, one: one,
loop_label: gen_label("find_vl"), done_label: gen_label("find_vd")}
var vrL = {arr: arr_slot, len: len, i: i, check: check, item: item, one: one,
loop_label: gen_label("find_vrl"), done_label: gen_label("find_vrd")}
var fL = {arr: arr_slot, len: len, i: i, check: check, item: item, one: one,
loop_label: gen_label("find_fl"), done_label: gen_label("find_fd")}
var ffL = {arr: arr_slot, len: len, i: i, check: check, item: item, one: one,
loop_label: gen_label("find_ffl"), done_label: gen_label("find_ffd")}
var frL = {arr: arr_slot, len: len, i: i, check: check, item: item, one: one,
loop_label: gen_label("find_frl"), done_label: gen_label("find_frd")}
var ctx = {fn: target, fn_arity: fn_arity, result: val, null_s: null_s,
frame: f, zero: zero, one: one, az: az, ao: ao, prefix: "find"}
var val_body = function(L) {
emit_3("eq", eq_check, L.item, target)
emit_jump_cond("jump_true", eq_check, found_label)
return null
}
var fn_body = function(L) {
emit_arity_call(ctx, [L.item, L.i], 2)
emit_jump_cond("jump_true", val, found_label)
return null
}
emit_2("length", len, arr_slot)
emit_2("int", zero, 0)
emit_2("int", one, 1)
emit_1("null", null_s)
emit_2("is_func", is_fn, target)
emit_jump_cond("jump_true", is_fn, fn_mode_label)
// === Value mode ===
if (nargs <= 2) {
emit_forward_loop(vL, val_body)
} else {
emit_jump_cond("jump_true", args.rev, vrev)
if (nargs >= 4 && args.from >= 0) {
emit_2("move", i, args.from)
}
if (nargs >= 4 && args.from >= 0) {
emit_label(vL.loop_label)
emit_3("lt", vL.check, vL.i, vL.len)
emit_jump_cond("jump_false", vL.check, vL.done_label)
emit_3("load_index", vL.item, vL.arr, vL.i)
val_body(vL)
emit_3("add", vL.i, vL.i, vL.one)
emit_jump(vL.loop_label)
emit_label(vL.done_label)
} else {
emit_forward_loop(vL, val_body)
}
emit_jump(vdone)
emit_label(vrev)
emit_reverse_loop(vrL, val_body)
emit_label(vdone)
}
emit_jump(not_found_label)
// === Function mode ===
emit_label(fn_mode_label)
emit_2("length", fn_arity, target)
if (nargs <= 2) {
emit_forward_loop(fL, fn_body)
} else {
emit_jump_cond("jump_true", args.rev, frev)
if (nargs >= 4 && args.from >= 0) {
emit_2("move", i, args.from)
}
if (nargs >= 4 && args.from >= 0) {
emit_label(ffL.loop_label)
emit_3("lt", ffL.check, ffL.i, ffL.len)
emit_jump_cond("jump_false", ffL.check, ffL.done_label)
emit_3("load_index", ffL.item, ffL.arr, ffL.i)
fn_body(ffL)
emit_3("add", ffL.i, ffL.i, ffL.one)
emit_jump(ffL.loop_label)
emit_label(ffL.done_label)
} else {
emit_forward_loop(ffL, fn_body)
}
emit_jump(fdone)
emit_label(frev)
emit_reverse_loop(frL, fn_body)
emit_label(fdone)
}
emit_label(not_found_label)
emit_1("null", dest)
emit_jump(final_label)
emit_label(found_label)
emit_2("move", dest, i)
emit_label(final_label)
return dest
}
// --- Inline expansion: array(arr, fn) → map ---
var expand_inline_map = function(dest, arr_slot, fn_slot) {
var result = alloc_slot()
@@ -1993,11 +2136,13 @@ var mcode = function(ast) {
return a1
}
// Callback intrinsics → inline mcode loops
if (nargs == 2 && fname == "arrfor" && inline_arrfor) {
if (fname == "arrfor" && nargs >= 2 && nargs <= 4 && inline_arrfor) {
a0 = gen_expr(args_list[0], -1)
a1 = gen_expr(args_list[1], -1)
a2 = nargs >= 3 ? gen_expr(args_list[2], -1) : -1
a3 = nargs >= 4 ? gen_expr(args_list[3], -1) : -1
d = alloc_slot()
return expand_inline_arrfor(d, a0, a1)
return expand_inline_arrfor(d, {arr: a0, fn: a1, rev: a2, exit: a3}, nargs)
}
if (nargs == 2 && fname == "every" && inline_every) {
a0 = gen_expr(args_list[0], -1)
@@ -2017,6 +2162,14 @@ var mcode = function(ast) {
d = alloc_slot()
return expand_inline_filter(d, a0, a1)
}
if (fname == "find" && nargs >= 2 && nargs <= 4 && inline_find) {
a0 = gen_expr(args_list[0], -1)
a1 = gen_expr(args_list[1], -1)
a2 = nargs >= 3 ? gen_expr(args_list[2], -1) : -1
a3 = nargs >= 4 ? gen_expr(args_list[3], -1) : -1
d = alloc_slot()
return expand_inline_find(d, {arr: a0, target: a1, rev: a2, from: a3}, nargs)
}
if (fname == "reduce" && nargs >= 2 && nargs <= 4 && inline_reduce) {
a0 = gen_expr(args_list[0], -1)
a1 = gen_expr(args_list[1], -1)