lower intrinsics in mcode

This commit is contained in:
2026-02-13 02:31:16 -06:00
parent e346348eb5
commit 6fff96d9d9
2 changed files with 19609 additions and 16348 deletions

351
mcode.cm
View File

@@ -986,6 +986,323 @@ var mcode = function(ast) {
return -1
}
// --- Inline expansion toggle flags ---
var inline_arrfor = true
var inline_filter = true
var inline_every = true
var inline_some = true
var inline_reduce = true
// --- Helper: emit a reduce loop body ---
// r = {acc, i, arr, fn, len}; emits loop updating acc in-place.
// Caller must emit the done_label after calling this.
var emit_reduce_loop = function(r, forward, done_label) {
var acc = r.acc
var i = r.i
var arr_slot = r.arr
var fn_slot = r.fn
var len = r.len
var check = alloc_slot()
var item = alloc_slot()
var null_s = alloc_slot()
var one = alloc_slot()
var zero = alloc_slot()
var f = alloc_slot()
var loop_label = gen_label("reduce_loop")
emit_2("int", one, 1)
emit_1("null", null_s)
emit_label(loop_label)
if (forward) {
emit_3("lt_int", check, i, len)
} else {
emit_2("int", zero, 0)
emit_3("ge_int", check, i, zero)
}
emit_jump_cond("jump_false", check, done_label)
emit_3("load_index", item, arr_slot, i)
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)
if (forward) {
emit_3("add_int", i, i, one)
} else {
emit_3("sub_int", i, i, one)
}
emit_jump(loop_label)
}
// --- Inline expansion: arrfor(arr, fn) ---
var expand_inline_arrfor = function(dest, arr_slot, fn_slot) {
var len = alloc_slot()
var i = alloc_slot()
var check = alloc_slot()
var item = alloc_slot()
var null_s = 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")
emit_2("length", len, arr_slot)
emit_2("int", i, 0)
emit_2("int", one, 1)
emit_1("null", null_s)
emit_label(loop_label)
emit_3("lt_int", check, i, len)
emit_jump_cond("jump_false", check, done_label)
emit_3("load_index", item, arr_slot, i)
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_3("add_int", i, i, one)
emit_jump(loop_label)
emit_label(done_label)
emit_1("null", dest)
return dest
}
// --- Inline expansion: every(arr, fn) ---
var expand_inline_every = function(dest, arr_slot, fn_slot) {
var len = alloc_slot()
var i = alloc_slot()
var check = alloc_slot()
var item = alloc_slot()
var null_s = alloc_slot()
var one = alloc_slot()
var f = alloc_slot()
var val = alloc_slot()
var loop_label = gen_label("every_loop")
var ret_true = gen_label("every_true")
var ret_false = gen_label("every_false")
var done_label = gen_label("every_done")
emit_2("length", len, arr_slot)
emit_2("int", i, 0)
emit_2("int", one, 1)
emit_1("null", null_s)
emit_label(loop_label)
emit_3("lt_int", check, i, len)
emit_jump_cond("jump_false", check, ret_true)
emit_3("load_index", item, arr_slot, i)
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_cond("jump_false", val, ret_false)
emit_3("add_int", i, i, one)
emit_jump(loop_label)
emit_label(ret_true)
emit_1("true", dest)
emit_jump(done_label)
emit_label(ret_false)
emit_1("false", dest)
emit_label(done_label)
return dest
}
// --- Inline expansion: some(arr, fn) ---
var expand_inline_some = function(dest, arr_slot, fn_slot) {
var len = alloc_slot()
var i = alloc_slot()
var check = alloc_slot()
var item = alloc_slot()
var null_s = alloc_slot()
var one = alloc_slot()
var f = alloc_slot()
var val = alloc_slot()
var loop_label = gen_label("some_loop")
var ret_true = gen_label("some_true")
var ret_false = gen_label("some_false")
var done_label = gen_label("some_done")
emit_2("length", len, arr_slot)
emit_2("int", i, 0)
emit_2("int", one, 1)
emit_1("null", null_s)
emit_label(loop_label)
emit_3("lt_int", check, i, len)
emit_jump_cond("jump_false", check, ret_false)
emit_3("load_index", item, arr_slot, i)
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_cond("jump_true", val, ret_true)
emit_3("add_int", i, i, one)
emit_jump(loop_label)
emit_label(ret_true)
emit_1("true", dest)
emit_jump(done_label)
emit_label(ret_false)
emit_1("false", dest)
emit_label(done_label)
return dest
}
// --- Inline expansion: filter(arr, fn) ---
var expand_inline_filter = function(dest, arr_slot, fn_slot) {
var result = alloc_slot()
var len = alloc_slot()
var i = alloc_slot()
var check = alloc_slot()
var item = alloc_slot()
var null_s = alloc_slot()
var one = alloc_slot()
var f = alloc_slot()
var val = alloc_slot()
var loop_label = gen_label("filter_loop")
var skip_label = gen_label("filter_skip")
var 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", one, 1)
emit_1("null", null_s)
emit_label(loop_label)
emit_3("lt_int", check, i, len)
emit_jump_cond("jump_false", check, done_label)
emit_3("load_index", item, arr_slot, i)
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_jump_cond("jump_false", val, skip_label)
emit_2("push", result, item)
emit_label(skip_label)
emit_3("add_int", i, i, one)
emit_jump(loop_label)
emit_label(done_label)
emit_2("move", dest, result)
return dest
}
// --- Inline expansion: reduce(arr, fn[, initial[, reverse]]) ---
var expand_inline_reduce = function(dest, args, nargs) {
var arr_slot = args.arr
var fn_slot = args.fn
var init_slot = args.init
var rev_slot = args.rev
var len = alloc_slot()
var acc = alloc_slot()
var i = alloc_slot()
var check = alloc_slot()
var zero = alloc_slot()
var one = alloc_slot()
var final_label = gen_label("reduce_final")
var has_init = null
var no_init_rev = null
var init_rev = null
var null_label = null
var d1 = null
var d2 = null
var d3 = null
var d4 = null
var r = null
emit_2("length", len, arr_slot)
emit_2("int", zero, 0)
emit_2("int", one, 1)
r = {acc: acc, i: i, arr: arr_slot, fn: fn_slot, len: len}
if (nargs == 2) {
null_label = gen_label("reduce_null")
d1 = gen_label("reduce_d1")
emit_3("lt_int", check, zero, len)
emit_jump_cond("jump_false", check, null_label)
emit_3("load_index", acc, arr_slot, zero)
emit_2("move", i, one)
emit_reduce_loop(r, true, d1)
emit_label(d1)
emit_2("move", dest, acc)
emit_jump(final_label)
emit_label(null_label)
emit_1("null", dest)
emit_label(final_label)
} else if (nargs == 3) {
has_init = gen_label("reduce_has_init")
null_label = gen_label("reduce_null")
d1 = gen_label("reduce_d1")
d2 = gen_label("reduce_d2")
emit_2("is_null", check, init_slot)
emit_jump_cond("jump_false", check, has_init)
// No initial, forward
emit_3("lt_int", check, zero, len)
emit_jump_cond("jump_false", check, null_label)
emit_3("load_index", acc, arr_slot, zero)
emit_2("move", i, one)
emit_reduce_loop(r, true, d1)
emit_label(d1)
emit_2("move", dest, acc)
emit_jump(final_label)
emit_label(null_label)
emit_1("null", dest)
emit_jump(final_label)
// Has initial, forward
emit_label(has_init)
emit_2("move", acc, init_slot)
emit_2("int", i, 0)
emit_reduce_loop(r, true, d2)
emit_label(d2)
emit_2("move", dest, acc)
emit_label(final_label)
} else {
// nargs == 4: full branching
has_init = gen_label("reduce_has_init")
no_init_rev = gen_label("reduce_no_init_rev")
init_rev = gen_label("reduce_init_rev")
null_label = gen_label("reduce_null")
d1 = gen_label("reduce_d1")
d2 = gen_label("reduce_d2")
d3 = gen_label("reduce_d3")
d4 = gen_label("reduce_d4")
emit_2("is_null", check, init_slot)
emit_jump_cond("jump_false", check, has_init)
// No initial
emit_3("lt_int", check, zero, len)
emit_jump_cond("jump_false", check, null_label)
emit_jump_cond("jump_true", rev_slot, no_init_rev)
// No initial, forward
emit_3("load_index", acc, arr_slot, zero)
emit_2("move", i, one)
emit_reduce_loop(r, true, d1)
emit_label(d1)
emit_2("move", dest, acc)
emit_jump(final_label)
// No initial, reverse
emit_label(no_init_rev)
emit_3("sub_int", i, len, one)
emit_3("load_index", acc, arr_slot, i)
emit_3("sub_int", i, i, one)
emit_reduce_loop(r, false, d2)
emit_label(d2)
emit_2("move", dest, acc)
emit_jump(final_label)
emit_label(null_label)
emit_1("null", dest)
emit_jump(final_label)
// Has initial
emit_label(has_init)
emit_jump_cond("jump_true", rev_slot, init_rev)
// Has initial, forward
emit_2("move", acc, init_slot)
emit_2("int", i, 0)
emit_reduce_loop(r, true, d3)
emit_label(d3)
emit_2("move", dest, acc)
emit_jump(final_label)
// Has initial, reverse
emit_label(init_rev)
emit_2("move", acc, init_slot)
emit_3("sub_int", i, len, one)
emit_reduce_loop(r, false, d4)
emit_label(d4)
emit_2("move", dest, acc)
emit_label(final_label)
}
return dest
}
// Forward declarations via var
var gen_expr = null
var gen_statement = null
@@ -1270,6 +1587,7 @@ var mcode = function(ast) {
var a0 = 0
var a1 = 0
var a2 = 0
var a3 = 0
var d = 0
var top = null
var arg_slots = null
@@ -1553,6 +1871,39 @@ var mcode = function(ast) {
emit_2("push", a0, a1)
return a1
}
// Callback intrinsics → inline mcode loops
if (nargs == 2 && fname == "arrfor" && inline_arrfor) {
a0 = gen_expr(args_list[0], -1)
a1 = gen_expr(args_list[1], -1)
d = alloc_slot()
return expand_inline_arrfor(d, a0, a1)
}
if (nargs == 2 && fname == "every" && inline_every) {
a0 = gen_expr(args_list[0], -1)
a1 = gen_expr(args_list[1], -1)
d = alloc_slot()
return expand_inline_every(d, a0, a1)
}
if (nargs == 2 && fname == "some" && inline_some) {
a0 = gen_expr(args_list[0], -1)
a1 = gen_expr(args_list[1], -1)
d = alloc_slot()
return expand_inline_some(d, a0, a1)
}
if (nargs == 2 && fname == "filter" && inline_filter) {
a0 = gen_expr(args_list[0], -1)
a1 = gen_expr(args_list[1], -1)
d = alloc_slot()
return expand_inline_filter(d, a0, a1)
}
if (fname == "reduce" && nargs >= 2 && nargs <= 4 && inline_reduce) {
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_reduce(d, {arr: a0, fn: a1, init: a2, rev: a3}, nargs)
}
}
// Collect arg slots

File diff suppressed because it is too large Load Diff