qbe rt
This commit is contained in:
100
qbe_emit.cm
100
qbe_emit.cm
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user