This commit is contained in:
2026-02-10 20:28:51 -06:00
parent 1320ef9f47
commit da6f096a56
7 changed files with 362 additions and 121 deletions

View File

@@ -89,6 +89,9 @@ var qbe_emit = function(ir, qbe) {
var pn = null
var sl = null
var fop_id = 0
var nr_elems = 0
var ei = 0
var elem_slot = 0
// Function signature: (ctx, frame_ptr) → JSValue
emit(`export function l $${name}(l %ctx, l %fp) {`)
@@ -105,6 +108,11 @@ var qbe_emit = function(ir, qbe) {
i = i + 1
}
// Write-back: store SSA var to frame slot so closures see updates
var wb = function(slot) {
emit(` storel ${s(slot)}, %p${text(slot)}`)
}
// Walk instructions
i = 0
while (i < length(instrs)) {
@@ -126,18 +134,22 @@ var qbe_emit = function(ir, qbe) {
if (op == "int") {
emit(` ${s(a1)} =l copy ${text(a2 * 2)}`)
wb(a1)
continue
}
if (op == "null") {
emit(` ${s(a1)} =l copy ${text(qbe.js_null)}`)
wb(a1)
continue
}
if (op == "true") {
emit(` ${s(a1)} =l copy ${text(qbe.js_true)}`)
wb(a1)
continue
}
if (op == "false") {
emit(` ${s(a1)} =l copy ${text(qbe.js_false)}`)
wb(a1)
continue
}
if (op == "access") {
@@ -177,6 +189,7 @@ var qbe_emit = function(ir, qbe) {
} else {
emit(` ${s(a1)} =l copy ${text(qbe.js_null)}`)
}
wb(a1)
continue
}
@@ -184,6 +197,7 @@ var qbe_emit = function(ir, qbe) {
if (op == "move") {
emit(` ${s(a1)} =l copy ${s(a2)}`)
wb(a1)
continue
}
@@ -193,30 +207,35 @@ var qbe_emit = function(ir, qbe) {
p = fresh()
emit(qbe.add_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "sub_int") {
p = fresh()
emit(qbe.sub_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "mul_int") {
p = fresh()
emit(qbe.mul_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "div_int") {
p = fresh()
emit(qbe.div_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "mod_int") {
p = fresh()
emit(qbe.mod_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
@@ -226,30 +245,35 @@ var qbe_emit = function(ir, qbe) {
p = fresh()
emit(qbe.add_float(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "sub_float") {
p = fresh()
emit(qbe.sub_float(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "mul_float") {
p = fresh()
emit(qbe.mul_float(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "div_float") {
p = fresh()
emit(qbe.div_float(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "mod_float") {
p = fresh()
emit(qbe.mod_float(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
@@ -259,6 +283,7 @@ var qbe_emit = function(ir, qbe) {
p = fresh()
emit(qbe.concat(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
@@ -269,6 +294,7 @@ var qbe_emit = function(ir, qbe) {
emit(qbe.is_int(p, s(a2)))
emit(qbe.new_bool(p + ".r", "%" + p))
emit(` ${s(a1)} =l copy %${p}.r`)
wb(a1)
continue
}
if (op == "is_text") {
@@ -276,6 +302,7 @@ var qbe_emit = function(ir, qbe) {
emit(qbe.is_imm_text(p, s(a2)))
emit(qbe.new_bool(p + ".r", "%" + p))
emit(` ${s(a1)} =l copy %${p}.r`)
wb(a1)
continue
}
if (op == "is_num") {
@@ -283,6 +310,7 @@ var qbe_emit = function(ir, qbe) {
emit(qbe.is_number(p, s(a2)))
emit(qbe.new_bool(p + ".r", "%" + p))
emit(` ${s(a1)} =l copy %${p}.r`)
wb(a1)
continue
}
if (op == "is_bool") {
@@ -290,6 +318,7 @@ var qbe_emit = function(ir, qbe) {
emit(qbe.is_bool(p, s(a2)))
emit(qbe.new_bool(p + ".r", "%" + p))
emit(` ${s(a1)} =l copy %${p}.r`)
wb(a1)
continue
}
if (op == "is_null") {
@@ -297,12 +326,14 @@ var qbe_emit = function(ir, qbe) {
emit(qbe.is_null(p, s(a2)))
emit(qbe.new_bool(p + ".r", "%" + p))
emit(` ${s(a1)} =l copy %${p}.r`)
wb(a1)
continue
}
if (op == "is_identical") {
p = fresh()
emit(qbe.is_identical(p, s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
@@ -312,36 +343,42 @@ var qbe_emit = function(ir, qbe) {
p = fresh()
emit(qbe.eq_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "ne_int") {
p = fresh()
emit(qbe.ne_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "lt_int") {
p = fresh()
emit(qbe.lt_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "gt_int") {
p = fresh()
emit(qbe.gt_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "le_int") {
p = fresh()
emit(qbe.le_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "ge_int") {
p = fresh()
emit(qbe.ge_int(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
@@ -351,12 +388,14 @@ var qbe_emit = function(ir, qbe) {
p = fresh()
emit(qbe.eq_float(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "ne_float") {
p = fresh()
emit(qbe.ne_float(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "lt_float" || op == "gt_float" || op == "le_float" || op == "ge_float") {
@@ -368,39 +407,46 @@ var qbe_emit = function(ir, qbe) {
else if (op == "ge_float") fop_id = 5
emit(qbe.cmp_float != null ? cmp_float(p, "%ctx", s(a2), s(a3), fop_id) : ` %${p} =l call $qbe_float_cmp(l %ctx, w ${text(fop_id)}, l ${s(a2)}, l ${s(a3)})`)
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "eq_text") {
p = fresh()
emit(qbe.eq_text(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "ne_text") {
p = fresh()
emit(qbe.ne_text(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "lt_text" || op == "gt_text" || op == "le_text" || op == "ge_text") {
p = fresh()
emit(` ${s(a1)} =l call $cell_rt_${op}(l %ctx, l ${s(a2)}, l ${s(a3)})`)
wb(a1)
continue
}
if (op == "eq_bool") {
p = fresh()
emit(qbe.eq_bool(p, s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "ne_bool") {
p = fresh()
emit(qbe.ne_bool(p, s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "eq_tol" || op == "ne_tol") {
emit(` ${s(a1)} =l call $cell_rt_${op}(l %ctx, l ${s(a2)}, l ${s(a3)})`)
wb(a1)
continue
}
@@ -410,14 +456,17 @@ var qbe_emit = function(ir, qbe) {
p = fresh()
emit(qbe.lnot(p, "%ctx", s(a2)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "and") {
emit(` ${s(a1)} =l and ${s(a2)}, ${s(a3)}`)
wb(a1)
continue
}
if (op == "or") {
emit(` ${s(a1)} =l or ${s(a2)}, ${s(a3)}`)
wb(a1)
continue
}
@@ -427,42 +476,49 @@ var qbe_emit = function(ir, qbe) {
p = fresh()
emit(qbe.bnot(p, "%ctx", s(a2)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "bitand") {
p = fresh()
emit(qbe.band(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "bitor") {
p = fresh()
emit(qbe.bor(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "bitxor") {
p = fresh()
emit(qbe.bxor(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "shl") {
p = fresh()
emit(qbe.shl(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "shr") {
p = fresh()
emit(qbe.shr(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "ushr") {
p = fresh()
emit(qbe.ushr(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
@@ -476,32 +532,38 @@ var qbe_emit = function(ir, qbe) {
} else {
emit(` ${s(a1)} =l call $cell_rt_load_dynamic(l %ctx, l ${s(a2)}, l ${s(a3)})`)
}
wb(a1)
continue
}
if (op == "load_index") {
emit(` ${s(a1)} =l call $cell_rt_load_index(l %ctx, l ${s(a2)}, l ${s(a3)})`)
wb(a1)
continue
}
if (op == "load_dynamic") {
emit(` ${s(a1)} =l call $cell_rt_load_dynamic(l %ctx, l ${s(a2)}, l ${s(a3)})`)
wb(a1)
continue
}
if (op == "store_field") {
// IR: ["store_field", obj, val, prop] → C: (ctx, val, obj, name)
pn = prop_name(a3)
if (pn != null) {
sl = intern_str(pn)
emit(` call $cell_rt_store_field(l %ctx, l ${s(a1)}, l ${s(a2)}, l ${sl})`)
emit(` call $cell_rt_store_field(l %ctx, l ${s(a2)}, l ${s(a1)}, l ${sl})`)
} else {
emit(` call $cell_rt_store_dynamic(l %ctx, l ${s(a1)}, l ${s(a2)}, l ${s(a3)})`)
emit(` call $cell_rt_store_dynamic(l %ctx, l ${s(a2)}, l ${s(a1)}, l ${s(a3)})`)
}
continue
}
if (op == "store_index") {
emit(` call $cell_rt_store_index(l %ctx, l ${s(a1)}, l ${s(a2)}, l ${s(a3)})`)
// IR: ["store_index", obj, val, idx] → C: (ctx, val, obj, idx)
emit(` call $cell_rt_store_index(l %ctx, l ${s(a2)}, l ${s(a1)}, l ${s(a3)})`)
continue
}
if (op == "store_dynamic") {
emit(` call $cell_rt_store_dynamic(l %ctx, l ${s(a1)}, l ${s(a2)}, l ${s(a3)})`)
// IR: ["store_dynamic", obj, val, key] → C: (ctx, val, obj, key)
emit(` call $cell_rt_store_dynamic(l %ctx, l ${s(a2)}, l ${s(a1)}, l ${s(a3)})`)
continue
}
@@ -509,6 +571,7 @@ var qbe_emit = function(ir, qbe) {
if (op == "get") {
emit(` ${s(a1)} =l call $cell_rt_get_closure(l %ctx, l %fp, l ${text(a2)}, l ${text(a3)})`)
wb(a1)
continue
}
if (op == "put") {
@@ -569,6 +632,7 @@ var qbe_emit = function(ir, qbe) {
if (op == "frame") {
emit(` ${s(a1)} =l call $cell_rt_frame(l %ctx, l ${s(a2)}, l ${text(a3)})`)
wb(a1)
continue
}
if (op == "setarg") {
@@ -577,10 +641,12 @@ var qbe_emit = function(ir, qbe) {
}
if (op == "invoke") {
emit(` ${s(a2)} =l call $cell_rt_invoke(l %ctx, l ${s(a1)})`)
wb(a2)
continue
}
if (op == "goframe") {
emit(` ${s(a1)} =l call $cell_rt_goframe(l %ctx, l ${s(a2)}, l ${text(a3)})`)
wb(a1)
continue
}
if (op == "goinvoke") {
@@ -591,7 +657,28 @@ var qbe_emit = function(ir, qbe) {
// --- Function object creation ---
if (op == "function") {
emit(` ${s(a1)} =l call $cell_rt_make_function(l %ctx, l ${text(a2)})`)
emit(` ${s(a1)} =l call $cell_rt_make_function(l %ctx, l ${text(a2)}, l %fp)`)
wb(a1)
continue
}
// --- Record/Array creation ---
if (op == "record") {
emit(` ${s(a1)} =l call $JS_NewObject(l %ctx)`)
wb(a1)
continue
}
if (op == "array") {
nr_elems = a2 != null ? a2 : 0
emit(` ${s(a1)} =l call $JS_NewArray(l %ctx)`)
ei = 0
while (ei < nr_elems) {
elem_slot = instr[3 + ei]
emit(` call $JS_SetPropertyUint32(l %ctx, l ${s(a1)}, l ${text(ei)}, l ${s(elem_slot)})`)
ei = ei + 1
}
wb(a1)
continue
}
@@ -603,6 +690,7 @@ var qbe_emit = function(ir, qbe) {
}
if (op == "pop") {
emit(` ${s(a1)} =l call $cell_rt_pop(l %ctx, l ${s(a2)})`)
wb(a1)
continue
}
@@ -619,10 +707,12 @@ var qbe_emit = function(ir, qbe) {
}
if (op == "delete") {
emit(` ${s(a1)} =l call $cell_rt_delete(l %ctx, l ${s(a2)}, l ${s(a3)})`)
wb(a1)
continue
}
if (op == "typeof") {
emit(` ${s(a1)} =l call $cell_rt_typeof(l %ctx, l ${s(a2)})`)
wb(a1)
continue
}