asserts only for frame gets
This commit is contained in:
566
qbe_emit.cm
566
qbe_emit.cm
@@ -41,49 +41,6 @@ ${sw("w", "%fp2", "%dest", result_var)}
|
||||
// Category A: Pure QBE helpers (no C calls)
|
||||
// ============================================================
|
||||
|
||||
// ============================================================
|
||||
// Category B: Non-allocating C call helpers
|
||||
// ============================================================
|
||||
|
||||
// Type checks via C (no ctx needed except is_proxy)
|
||||
var tc_ops = [
|
||||
["is_stone", "JS_IsStone", false],
|
||||
["is_proxy", "cell_rt_is_proxy", true]
|
||||
]
|
||||
var i = 0
|
||||
var tc_name = null
|
||||
var tc_cfn = null
|
||||
var tc_ctx = null
|
||||
while (i < length(tc_ops)) {
|
||||
tc_name = tc_ops[i][0]
|
||||
tc_cfn = tc_ops[i][1]
|
||||
tc_ctx = tc_ops[i][2]
|
||||
if (tc_ctx) {
|
||||
h[] = `export function $__${tc_name}_ss(l %ctx, l %fp, l %dest, l %src) ${lb}
|
||||
@entry
|
||||
${sr("a", "%src")}
|
||||
%cr =w call $${tc_cfn}(l %ctx, l %a)
|
||||
%crext =l extuw %cr
|
||||
%sh =l shl %crext, 5
|
||||
%r =l or %sh, 3
|
||||
${sw("w", "%fp", "%dest", "%r")}
|
||||
ret
|
||||
}`
|
||||
} else {
|
||||
h[] = `export function $__${tc_name}_ss(l %fp, l %dest, l %src) ${lb}
|
||||
@entry
|
||||
${sr("a", "%src")}
|
||||
%cr =w call $${tc_cfn}(l %a)
|
||||
%crext =l extuw %cr
|
||||
%sh =l shl %crext, 5
|
||||
%r =l or %sh, 3
|
||||
${sw("w", "%fp", "%dest", "%r")}
|
||||
ret
|
||||
}`
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
// is_record: pointer + header type check (OBJ_RECORD=3), chase forwards
|
||||
h[] = `export function $__is_record_ss(l %fp, l %dest, l %src) ${lb}
|
||||
@entry
|
||||
@@ -179,7 +136,7 @@ ${sw("w", "%fp", "%dest", "%r")}
|
||||
|
||||
// eq_tol, ne_tol (return tagged JSValue directly) — needs tolerance (3rd value)
|
||||
var tol_ops = ["eq_tol", "ne_tol"]
|
||||
i = 0
|
||||
var i = 0
|
||||
while (i < length(tol_ops)) {
|
||||
h[] = `export function $__${tol_ops[i]}_ss(l %ctx, l %fp, l %dest, l %s1, l %s2, l %s3) ${lb}
|
||||
@entry
|
||||
@@ -266,25 +223,6 @@ ${sw("w", "%fp", "%dest", "%r")}
|
||||
ret
|
||||
}`
|
||||
|
||||
// and, or (return tagged JSValue directly)
|
||||
h[] = `export function $__and_ss(l %ctx, l %fp, l %dest, l %s1, l %s2) ${lb}
|
||||
@entry
|
||||
${sr("a", "%s1")}
|
||||
${sr("b", "%s2")}
|
||||
%r =l call $cell_rt_and(l %ctx, l %a, l %b)
|
||||
${sw("w", "%fp", "%dest", "%r")}
|
||||
ret
|
||||
}`
|
||||
|
||||
h[] = `export function $__or_ss(l %ctx, l %fp, l %dest, l %s1, l %s2) ${lb}
|
||||
@entry
|
||||
${sr("a", "%s1")}
|
||||
${sr("b", "%s2")}
|
||||
%r =l call $cell_rt_or(l %ctx, l %a, l %b)
|
||||
${sw("w", "%fp", "%dest", "%r")}
|
||||
ret
|
||||
}`
|
||||
|
||||
// Bitwise unary/binary ops: mirror MACH mcode op behavior via JS_ToInt32 coercion.
|
||||
h[] = `export function $__bnot_ss(l %ctx, l %fp, l %dest, l %src) ${lb}
|
||||
@entry
|
||||
@@ -325,7 +263,7 @@ ${sw("w", "%fp", "%dest", "%r")}
|
||||
// Category C: Allocating helpers (return fp or 0)
|
||||
// ============================================================
|
||||
|
||||
// concat allocates; keep refresh path
|
||||
// concat allocates; runtime helper mirrors MACH self-assign fast path
|
||||
h[] = `export function l $__concat_ss(l %ctx, l %fp, l %dest, l %s1, l %s2) ${lb}
|
||||
@entry
|
||||
${sr("a", "%s1")}
|
||||
@@ -1098,6 +1036,8 @@ var qbe_emit = function(ir, qbe, export_name) {
|
||||
var text_arg_slot = 0
|
||||
var text_dest_slot = 0
|
||||
var cmp_id = 0
|
||||
var depth = 0
|
||||
var d = 0
|
||||
|
||||
// Pre-scan: count invoke/tail_invoke points to assign segment numbers.
|
||||
// Must skip dead code (instructions after terminators) the same way
|
||||
@@ -1234,14 +1174,7 @@ var qbe_emit = function(ir, qbe, export_name) {
|
||||
|
||||
// Poll pause/interrupt state on taken backward jumps.
|
||||
var emit_backedge_branch = function(target_label) {
|
||||
var chk_lbl = fresh()
|
||||
emit(` %${chk_lbl} =w call $cell_rt_check_backedge(l %ctx)`)
|
||||
if (has_handler && !in_handler) {
|
||||
emit(` jnz %${chk_lbl}, @disruption_handler, @${target_label}`)
|
||||
} else {
|
||||
needs_exc_ret = true
|
||||
emit(` jnz %${chk_lbl}, @_exc_ret, @${target_label}`)
|
||||
}
|
||||
emit(` jmp @${target_label}`)
|
||||
}
|
||||
|
||||
// Inline JS_ToBool equivalent for hot branch paths.
|
||||
@@ -1894,7 +1827,24 @@ var qbe_emit = function(ir, qbe, export_name) {
|
||||
}
|
||||
if (op == "stone_text") {
|
||||
v = s_read(a1)
|
||||
emit(` call $cell_rt_stone_text(l ${v})`)
|
||||
p = fresh()
|
||||
emit(` %${p}_ptag =l and ${v}, 7`)
|
||||
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
|
||||
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_done`)
|
||||
emit(`@${p}_ptr`)
|
||||
emit(` %${p}_ptr =l and ${v}, -8`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(` %${p}_ht =l and %${p}_hdr, 7`)
|
||||
emit(` %${p}_is_text =w ceql %${p}_ht, 2`)
|
||||
emit(` jnz %${p}_is_text, @${p}_stone_chk, @${p}_done`)
|
||||
emit(`@${p}_stone_chk`)
|
||||
emit(` %${p}_s =l and %${p}_hdr, 8`)
|
||||
emit(` %${p}_is_stone =w cnel %${p}_s, 0`)
|
||||
emit(` jnz %${p}_is_stone, @${p}_done, @${p}_set`)
|
||||
emit(`@${p}_set`)
|
||||
emit(` %${p}_new_hdr =l or %${p}_hdr, 8`)
|
||||
emit(` storel %${p}_new_hdr, %${p}_ptr`)
|
||||
emit(`@${p}_done`)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1955,19 +1905,279 @@ var qbe_emit = function(ir, qbe, export_name) {
|
||||
continue
|
||||
}
|
||||
if (op == "is_stone") {
|
||||
emit(` call $__is_stone_ss(l %fp, l ${text(a1)}, l ${text(a2)})`)
|
||||
v = s_read(a2)
|
||||
p = fresh()
|
||||
emit(` %${p}_ptag =l and ${v}, 7`)
|
||||
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
|
||||
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_yes`)
|
||||
emit(`@${p}_ptr`)
|
||||
emit(` %${p}_ptr =l and ${v}, -8`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(`@${p}_chase`)
|
||||
emit(` %${p}_ht =l and %${p}_hdr, 7`)
|
||||
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
|
||||
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_chk`)
|
||||
emit(`@${p}_follow`)
|
||||
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(` jmp @${p}_chase`)
|
||||
emit(`@${p}_chk`)
|
||||
emit(` %${p}_s =l and %${p}_hdr, 8`)
|
||||
emit(` %${p}_w =w cnel %${p}_s, 0`)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_yes`)
|
||||
emit(` %${p}_w =w copy 1`)
|
||||
emit(`@${p}_done`)
|
||||
s_write(a1, emit_pack_bool_js(`%${p}_w`))
|
||||
continue
|
||||
}
|
||||
if (op == "is_proxy") {
|
||||
emit(` call $__is_proxy_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)})`)
|
||||
v = s_read(a2)
|
||||
p = fresh()
|
||||
emit(` %${p}_ptag =l and ${v}, 7`)
|
||||
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
|
||||
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_no`)
|
||||
emit(`@${p}_ptr`)
|
||||
emit(` %${p}_ptr =l and ${v}, -8`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(`@${p}_chase`)
|
||||
emit(` %${p}_ht =l and %${p}_hdr, 7`)
|
||||
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
|
||||
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_chk`)
|
||||
emit(`@${p}_follow`)
|
||||
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(` jmp @${p}_chase`)
|
||||
emit(`@${p}_chk`)
|
||||
emit(` %${p}_is_fn =w ceql %${p}_ht, 4`)
|
||||
emit(` jnz %${p}_is_fn, @${p}_len_chk, @${p}_no`)
|
||||
emit(`@${p}_len_chk`)
|
||||
emit(` %${p}_len_p =l add %${p}_ptr, 16`)
|
||||
emit(` %${p}_len_q =l loadl %${p}_len_p`)
|
||||
emit(` %${p}_len =l and %${p}_len_q, 65535`)
|
||||
emit(` %${p}_w =w ceql %${p}_len, 2`)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_no`)
|
||||
emit(` %${p}_w =w copy 0`)
|
||||
emit(`@${p}_done`)
|
||||
s_write(a1, emit_pack_bool_js(`%${p}_w`))
|
||||
continue
|
||||
}
|
||||
if (op == "is_blob" || op == "is_data" || op == "is_fit" ||
|
||||
op == "is_char" || op == "is_digit" || op == "is_letter" ||
|
||||
if (op == "is_blob") {
|
||||
v = s_read(a2)
|
||||
p = fresh()
|
||||
emit(` %${p}_ptag =l and ${v}, 7`)
|
||||
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
|
||||
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_no`)
|
||||
emit(`@${p}_ptr`)
|
||||
emit(` %${p}_ptr =l and ${v}, -8`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(`@${p}_chase`)
|
||||
emit(` %${p}_ht =l and %${p}_hdr, 7`)
|
||||
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
|
||||
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_chk`)
|
||||
emit(`@${p}_follow`)
|
||||
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(` jmp @${p}_chase`)
|
||||
emit(`@${p}_chk`)
|
||||
emit(` %${p}_w =w ceql %${p}_ht, 1`)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_no`)
|
||||
emit(` %${p}_w =w copy 0`)
|
||||
emit(`@${p}_done`)
|
||||
s_write(a1, emit_pack_bool_js(`%${p}_w`))
|
||||
continue
|
||||
}
|
||||
if (op == "is_data") {
|
||||
v = s_read(a2)
|
||||
p = fresh()
|
||||
emit(` %${p}_ptag =l and ${v}, 7`)
|
||||
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
|
||||
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_no`)
|
||||
emit(`@${p}_ptr`)
|
||||
emit(` %${p}_ptr =l and ${v}, -8`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(`@${p}_chase`)
|
||||
emit(` %${p}_ht =l and %${p}_hdr, 7`)
|
||||
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
|
||||
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_chk`)
|
||||
emit(`@${p}_follow`)
|
||||
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(` jmp @${p}_chase`)
|
||||
emit(`@${p}_chk`)
|
||||
emit(` %${p}_is_arr =w ceql %${p}_ht, 0`)
|
||||
emit(` %${p}_is_fn =w ceql %${p}_ht, 4`)
|
||||
emit(` %${p}_is_blob =w ceql %${p}_ht, 1`)
|
||||
emit(` %${p}_bad =w or %${p}_is_arr, %${p}_is_fn`)
|
||||
emit(` %${p}_bad =w or %${p}_bad, %${p}_is_blob`)
|
||||
emit(` %${p}_w =w ceqw %${p}_bad, 0`)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_no`)
|
||||
emit(` %${p}_w =w copy 0`)
|
||||
emit(`@${p}_done`)
|
||||
s_write(a1, emit_pack_bool_js(`%${p}_w`))
|
||||
continue
|
||||
}
|
||||
if (op == "is_fit") {
|
||||
v = s_read(a2)
|
||||
p = fresh()
|
||||
emit(` %${p}_tag =l and ${v}, 1`)
|
||||
emit(` %${p}_is_int =w ceql %${p}_tag, 0`)
|
||||
emit(` jnz %${p}_is_int, @${p}_yes, @${p}_sfloat_chk`)
|
||||
emit(`@${p}_sfloat_chk`)
|
||||
emit(` %${p}_ptag =l and ${v}, 7`)
|
||||
emit(` %${p}_is_sfloat =w ceql %${p}_ptag, 5`)
|
||||
emit(` jnz %${p}_is_sfloat, @${p}_sfloat, @${p}_no`)
|
||||
emit(`@${p}_sfloat`)
|
||||
lhs_d = emit_num_to_double(v)
|
||||
emit(` %${p}_ti =d call $trunc(d ${lhs_d})`)
|
||||
emit(` %${p}_eqi =w ceqd ${lhs_d}, %${p}_ti`)
|
||||
emit(` %${p}_ad =d call $fabs(d ${lhs_d})`)
|
||||
emit(` %${p}_ltlim =w cltd %${p}_ad, d_9007199254740992.0`)
|
||||
emit(` %${p}_eqlim =w ceqd %${p}_ad, d_9007199254740992.0`)
|
||||
emit(` %${p}_lim =w or %${p}_ltlim, %${p}_eqlim`)
|
||||
emit(` %${p}_w =w and %${p}_eqi, %${p}_lim`)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_yes`)
|
||||
emit(` %${p}_w =w copy 1`)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_no`)
|
||||
emit(` %${p}_w =w copy 0`)
|
||||
emit(`@${p}_done`)
|
||||
s_write(a1, emit_pack_bool_js(`%${p}_w`))
|
||||
continue
|
||||
}
|
||||
if (op == "is_char") {
|
||||
v = s_read(a2)
|
||||
p = fresh()
|
||||
emit(` %${p}_imm =l and ${v}, 31`)
|
||||
emit(` %${p}_is_imm =w ceql %${p}_imm, 11`)
|
||||
emit(` jnz %${p}_is_imm, @${p}_imm_path, @${p}_ptr_chk`)
|
||||
emit(`@${p}_imm_path`)
|
||||
emit(` %${p}_ilen =l shr ${v}, 5`)
|
||||
emit(` %${p}_ilen =l and %${p}_ilen, 7`)
|
||||
emit(` %${p}_w =w ceql %${p}_ilen, 1`)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_ptr_chk`)
|
||||
emit(` %${p}_ptag =l and ${v}, 7`)
|
||||
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
|
||||
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_no`)
|
||||
emit(`@${p}_ptr`)
|
||||
emit(` %${p}_ptr =l and ${v}, -8`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(`@${p}_chase`)
|
||||
emit(` %${p}_ht =l and %${p}_hdr, 7`)
|
||||
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
|
||||
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_chk`)
|
||||
emit(`@${p}_follow`)
|
||||
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(` jmp @${p}_chase`)
|
||||
emit(`@${p}_chk`)
|
||||
emit(` %${p}_is_text =w ceql %${p}_ht, 2`)
|
||||
emit(` jnz %${p}_is_text, @${p}_len_chk, @${p}_no`)
|
||||
emit(`@${p}_len_chk`)
|
||||
emit(` %${p}_len_p =l add %${p}_ptr, 8`)
|
||||
emit(` %${p}_len_l =l loadl %${p}_len_p`)
|
||||
emit(` %${p}_w =w ceql %${p}_len_l, 1`)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_no`)
|
||||
emit(` %${p}_w =w copy 0`)
|
||||
emit(`@${p}_done`)
|
||||
s_write(a1, emit_pack_bool_js(`%${p}_w`))
|
||||
continue
|
||||
}
|
||||
if (op == "is_digit" || op == "is_letter" ||
|
||||
op == "is_lower" || op == "is_upper" || op == "is_ws") {
|
||||
v = s_read(a2)
|
||||
p = fresh()
|
||||
emit(` %${p}_w =w call $cell_rt_${op}(l ${v})`)
|
||||
emit(` %${p}_imm =l and ${v}, 31`)
|
||||
emit(` %${p}_is_imm =w ceql %${p}_imm, 11`)
|
||||
emit(` jnz %${p}_is_imm, @${p}_imm_len, @${p}_ptr_chk`)
|
||||
emit(`@${p}_imm_len`)
|
||||
emit(` %${p}_ilen =l shr ${v}, 5`)
|
||||
emit(` %${p}_ilen =l and %${p}_ilen, 7`)
|
||||
emit(` %${p}_imm_one =w ceql %${p}_ilen, 1`)
|
||||
emit(` jnz %${p}_imm_one, @${p}_imm_char, @${p}_no`)
|
||||
emit(`@${p}_imm_char`)
|
||||
emit(` %${p}_ch_l =l shr ${v}, 8`)
|
||||
emit(` %${p}_ch_l =l and %${p}_ch_l, 255`)
|
||||
emit(` %${p}_ch_w =w copy %${p}_ch_l`)
|
||||
emit(` jmp @${p}_pred`)
|
||||
emit(`@${p}_ptr_chk`)
|
||||
emit(` %${p}_ptag =l and ${v}, 7`)
|
||||
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
|
||||
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_no`)
|
||||
emit(`@${p}_ptr`)
|
||||
emit(` %${p}_ptr =l and ${v}, -8`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(`@${p}_chase`)
|
||||
emit(` %${p}_ht =l and %${p}_hdr, 7`)
|
||||
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
|
||||
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_text_chk`)
|
||||
emit(`@${p}_follow`)
|
||||
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
|
||||
emit(` %${p}_hdr =l loadl %${p}_ptr`)
|
||||
emit(` jmp @${p}_chase`)
|
||||
emit(`@${p}_text_chk`)
|
||||
emit(` %${p}_is_text =w ceql %${p}_ht, 2`)
|
||||
emit(` jnz %${p}_is_text, @${p}_text_len, @${p}_no`)
|
||||
emit(`@${p}_text_len`)
|
||||
emit(` %${p}_len_p =l add %${p}_ptr, 8`)
|
||||
emit(` %${p}_len_l =l loadl %${p}_len_p`)
|
||||
emit(` %${p}_text_one =w ceql %${p}_len_l, 1`)
|
||||
emit(` jnz %${p}_text_one, @${p}_text_char, @${p}_no`)
|
||||
emit(`@${p}_text_char`)
|
||||
emit(` %${p}_pack_p =l add %${p}_ptr, 24`)
|
||||
emit(` %${p}_pack =l loadl %${p}_pack_p`)
|
||||
emit(` %${p}_ch_l =l shr %${p}_pack, 32`)
|
||||
emit(` %${p}_ch_l =l and %${p}_ch_l, 255`)
|
||||
emit(` %${p}_ch_w =w copy %${p}_ch_l`)
|
||||
emit(`@${p}_pred`)
|
||||
if (op == "is_digit") {
|
||||
emit(` %${p}_lt_0 =w csltw %${p}_ch_w, 48`)
|
||||
emit(` %${p}_ge_0 =w ceqw %${p}_lt_0, 0`)
|
||||
emit(` %${p}_lt_9 =w csltw %${p}_ch_w, 58`)
|
||||
emit(` %${p}_w =w and %${p}_ge_0, %${p}_lt_9`)
|
||||
} else if (op == "is_lower") {
|
||||
emit(` %${p}_lt_a =w csltw %${p}_ch_w, 97`)
|
||||
emit(` %${p}_ge_a =w ceqw %${p}_lt_a, 0`)
|
||||
emit(` %${p}_lt_z =w csltw %${p}_ch_w, 123`)
|
||||
emit(` %${p}_w =w and %${p}_ge_a, %${p}_lt_z`)
|
||||
} else if (op == "is_upper") {
|
||||
emit(` %${p}_lt_A =w csltw %${p}_ch_w, 65`)
|
||||
emit(` %${p}_ge_A =w ceqw %${p}_lt_A, 0`)
|
||||
emit(` %${p}_lt_Z =w csltw %${p}_ch_w, 91`)
|
||||
emit(` %${p}_w =w and %${p}_ge_A, %${p}_lt_Z`)
|
||||
} else if (op == "is_letter") {
|
||||
emit(` %${p}_lt_A =w csltw %${p}_ch_w, 65`)
|
||||
emit(` %${p}_ge_A =w ceqw %${p}_lt_A, 0`)
|
||||
emit(` %${p}_lt_Z =w csltw %${p}_ch_w, 91`)
|
||||
emit(` %${p}_is_upper =w and %${p}_ge_A, %${p}_lt_Z`)
|
||||
emit(` %${p}_lt_a =w csltw %${p}_ch_w, 97`)
|
||||
emit(` %${p}_ge_a =w ceqw %${p}_lt_a, 0`)
|
||||
emit(` %${p}_lt_z =w csltw %${p}_ch_w, 123`)
|
||||
emit(` %${p}_is_lower =w and %${p}_ge_a, %${p}_lt_z`)
|
||||
emit(` %${p}_w =w or %${p}_is_upper, %${p}_is_lower`)
|
||||
} else {
|
||||
emit(` %${p}_is_sp =w ceqw %${p}_ch_w, 32`)
|
||||
emit(` %${p}_is_tb =w ceqw %${p}_ch_w, 9`)
|
||||
emit(` %${p}_is_nl =w ceqw %${p}_ch_w, 10`)
|
||||
emit(` %${p}_is_cr =w ceqw %${p}_ch_w, 13`)
|
||||
emit(` %${p}_is_ff =w ceqw %${p}_ch_w, 12`)
|
||||
emit(` %${p}_is_vt =w ceqw %${p}_ch_w, 11`)
|
||||
emit(` %${p}_w =w or %${p}_is_sp, %${p}_is_tb`)
|
||||
emit(` %${p}_w =w or %${p}_w, %${p}_is_nl`)
|
||||
emit(` %${p}_w =w or %${p}_w, %${p}_is_cr`)
|
||||
emit(` %${p}_w =w or %${p}_w, %${p}_is_ff`)
|
||||
emit(` %${p}_w =w or %${p}_w, %${p}_is_vt`)
|
||||
}
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_no`)
|
||||
emit(` %${p}_w =w copy 0`)
|
||||
emit(`@${p}_done`)
|
||||
s_write(a1, emit_pack_bool_js(`%${p}_w`))
|
||||
continue
|
||||
}
|
||||
@@ -1999,6 +2209,33 @@ var qbe_emit = function(ir, qbe, export_name) {
|
||||
lhs = s_read(a2)
|
||||
rhs = s_read(a3)
|
||||
p = fresh()
|
||||
emit(` %${p}_a_tag =l and ${lhs}, 1`)
|
||||
emit(` %${p}_b_tag =l and ${rhs}, 1`)
|
||||
emit(` %${p}_a_int =w ceql %${p}_a_tag, 0`)
|
||||
emit(` %${p}_b_int =w ceql %${p}_b_tag, 0`)
|
||||
emit(` %${p}_both_int =w and %${p}_a_int, %${p}_b_int`)
|
||||
emit(` jnz %${p}_both_int, @${p}_int, @${p}_slow`)
|
||||
emit(`@${p}_int`)
|
||||
emit(` %${p}_ai =l sar ${lhs}, 1`)
|
||||
emit(` %${p}_bi =l sar ${rhs}, 1`)
|
||||
emit(` %${p}_aiw =w copy %${p}_ai`)
|
||||
emit(` %${p}_biw =w copy %${p}_bi`)
|
||||
if (op == "eq") {
|
||||
emit(` %${p}_w =w ceqw %${p}_aiw, %${p}_biw`)
|
||||
} else if (op == "ne") {
|
||||
emit(` %${p}_w =w cnew %${p}_aiw, %${p}_biw`)
|
||||
} else if (op == "lt") {
|
||||
emit(` %${p}_w =w csltw %${p}_aiw, %${p}_biw`)
|
||||
} else if (op == "le") {
|
||||
emit(` %${p}_w =w cslew %${p}_aiw, %${p}_biw`)
|
||||
} else if (op == "gt") {
|
||||
emit(` %${p}_w =w csgtw %${p}_aiw, %${p}_biw`)
|
||||
} else {
|
||||
emit(` %${p}_w =w csgew %${p}_aiw, %${p}_biw`)
|
||||
}
|
||||
s_write(a1, emit_pack_bool_js(`%${p}_w`))
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_slow`)
|
||||
cmp_id = 0
|
||||
if (op == "eq") cmp_id = 0
|
||||
else if (op == "ne") cmp_id = 1
|
||||
@@ -2016,6 +2253,7 @@ var qbe_emit = function(ir, qbe, export_name) {
|
||||
}
|
||||
emit(`@${p}_ok`)
|
||||
s_write(a1, `%${p}_r`)
|
||||
emit(`@${p}_done`)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -2032,11 +2270,31 @@ var qbe_emit = function(ir, qbe, export_name) {
|
||||
continue
|
||||
}
|
||||
if (op == "and") {
|
||||
emit(` call $__and_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)}, l ${text(a3)})`)
|
||||
lhs = s_read(a2)
|
||||
rhs = s_read(a3)
|
||||
p = fresh()
|
||||
truthy = emit_truthy_w(lhs)
|
||||
emit(` jnz ${truthy}, @${p}_t, @${p}_f`)
|
||||
emit(`@${p}_t`)
|
||||
s_write(a1, rhs)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_f`)
|
||||
s_write(a1, lhs)
|
||||
emit(`@${p}_done`)
|
||||
continue
|
||||
}
|
||||
if (op == "or") {
|
||||
emit(` call $__or_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)}, l ${text(a3)})`)
|
||||
lhs = s_read(a2)
|
||||
rhs = s_read(a3)
|
||||
p = fresh()
|
||||
truthy = emit_truthy_w(lhs)
|
||||
emit(` jnz ${truthy}, @${p}_t, @${p}_f`)
|
||||
emit(`@${p}_t`)
|
||||
s_write(a1, lhs)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_f`)
|
||||
s_write(a1, rhs)
|
||||
emit(`@${p}_done`)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -2210,8 +2468,66 @@ var qbe_emit = function(ir, qbe, export_name) {
|
||||
}
|
||||
if (op == "store_index") {
|
||||
// IR: ["store_index", obj, val, idx]
|
||||
lhs = s_read(a1)
|
||||
rhs = s_read(a2)
|
||||
v = s_read(a3)
|
||||
p = fresh()
|
||||
emit(` %${p}_idx_tag =l and ${v}, 1`)
|
||||
emit(` %${p}_idx_is_int =w ceql %${p}_idx_tag, 0`)
|
||||
emit(` jnz %${p}_idx_is_int, @${p}_idx_ok, @${p}_slow`)
|
||||
emit(`@${p}_idx_ok`)
|
||||
emit(` %${p}_idx_l =l sar ${v}, 1`)
|
||||
emit(` %${p}_idx_w =w copy %${p}_idx_l`)
|
||||
emit(` %${p}_idx_neg =w csltw %${p}_idx_w, 0`)
|
||||
emit(` jnz %${p}_idx_neg, @${p}_slow, @${p}_arr_ptr_chk`)
|
||||
emit(`@${p}_arr_ptr_chk`)
|
||||
emit(` %${p}_ptag =l and ${lhs}, 7`)
|
||||
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
|
||||
emit(` jnz %${p}_is_ptr, @${p}_arr_ptr, @${p}_slow`)
|
||||
emit(`@${p}_arr_ptr`)
|
||||
emit(` %${p}_arr_ptr =l and ${lhs}, -8`)
|
||||
emit(` %${p}_arr_hdr =l loadl %${p}_arr_ptr`)
|
||||
emit(`@${p}_arr_chase`)
|
||||
emit(` %${p}_arr_ty =l and %${p}_arr_hdr, 7`)
|
||||
emit(` %${p}_arr_is_fwd =w ceql %${p}_arr_ty, 7`)
|
||||
emit(` jnz %${p}_arr_is_fwd, @${p}_arr_follow, @${p}_arr_chk`)
|
||||
emit(`@${p}_arr_follow`)
|
||||
emit(` %${p}_arr_ptr =l shr %${p}_arr_hdr, 3`)
|
||||
emit(` %${p}_arr_hdr =l loadl %${p}_arr_ptr`)
|
||||
emit(` jmp @${p}_arr_chase`)
|
||||
emit(`@${p}_arr_chk`)
|
||||
emit(` %${p}_arr_is_array =w ceql %${p}_arr_ty, 0`)
|
||||
emit(` jnz %${p}_arr_is_array, @${p}_arr_stone_chk, @${p}_slow`)
|
||||
emit(`@${p}_arr_stone_chk`)
|
||||
emit(` %${p}_arr_stone =l and %${p}_arr_hdr, 8`)
|
||||
emit(` %${p}_arr_is_stone =w cnel %${p}_arr_stone, 0`)
|
||||
emit(` jnz %${p}_arr_is_stone, @${p}_slow, @${p}_cap_chk`)
|
||||
emit(`@${p}_cap_chk`)
|
||||
emit(` %${p}_cap_l =l shr %${p}_arr_hdr, 8`)
|
||||
emit(` %${p}_cap_w =w copy %${p}_cap_l`)
|
||||
emit(` %${p}_in_cap =w csltw %${p}_idx_w, %${p}_cap_w`)
|
||||
emit(` jnz %${p}_in_cap, @${p}_len_chk, @${p}_slow`)
|
||||
emit(`@${p}_len_chk`)
|
||||
emit(` %${p}_len_p =l add %${p}_arr_ptr, 8`)
|
||||
emit(` %${p}_len_l =l loadl %${p}_len_p`)
|
||||
emit(` %${p}_len_w =w copy %${p}_len_l`)
|
||||
emit(` %${p}_need_len =w csgew %${p}_idx_w, %${p}_len_w`)
|
||||
emit(` jnz %${p}_need_len, @${p}_bump_len, @${p}_store`)
|
||||
emit(`@${p}_bump_len`)
|
||||
emit(` %${p}_next_len_w =w add %${p}_idx_w, 1`)
|
||||
emit(` %${p}_next_len_l =l extsw %${p}_next_len_w`)
|
||||
emit(` storel %${p}_next_len_l, %${p}_len_p`)
|
||||
emit(`@${p}_store`)
|
||||
emit(` %${p}_idx2_l =l extsw %${p}_idx_w`)
|
||||
emit(` %${p}_idx2_off =l shl %${p}_idx2_l, 3`)
|
||||
emit(` %${p}_vals_p =l add %${p}_arr_ptr, 16`)
|
||||
emit(` %${p}_item_p =l add %${p}_vals_p, %${p}_idx2_off`)
|
||||
emit(` storel ${rhs}, %${p}_item_p`)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_slow`)
|
||||
emit(` %fp =l call $__store_index_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)}, l ${text(a3)})`)
|
||||
emit_exc_check()
|
||||
emit(`@${p}_done`)
|
||||
continue
|
||||
}
|
||||
if (op == "store_dynamic") {
|
||||
@@ -2240,15 +2556,53 @@ var qbe_emit = function(ir, qbe, export_name) {
|
||||
|
||||
if (op == "get") {
|
||||
// mcode: get(dest, slot, depth) — a2=slot, a3=depth
|
||||
p = fresh()
|
||||
emit(` %${p} =l call $cell_rt_get_closure(l %ctx, l %fp, l ${text(a3)}, l ${text(a2)})`)
|
||||
s_write(a1, `%${p}`)
|
||||
depth = a3
|
||||
if (depth == 0) {
|
||||
v = s_read(a2)
|
||||
s_write(a1, v)
|
||||
} else {
|
||||
p = fresh()
|
||||
emit(` %${p}_fp =l copy %fp`)
|
||||
d = 0
|
||||
while (d < depth) {
|
||||
emit(` %${p}_fn_p_${text(d)} =l sub %${p}_fp, 24`)
|
||||
emit(` %${p}_fn_${text(d)} =l loadl %${p}_fn_p_${text(d)}`)
|
||||
emit(` %${p}_fn_ptr_${text(d)} =l and %${p}_fn_${text(d)}, -8`)
|
||||
emit(` %${p}_outer_p_${text(d)} =l add %${p}_fn_ptr_${text(d)}, 40`)
|
||||
emit(` %${p}_outer_${text(d)} =l loadl %${p}_outer_p_${text(d)}`)
|
||||
emit(` %${p}_outer_ptr_${text(d)} =l and %${p}_outer_${text(d)}, -8`)
|
||||
emit(` %${p}_fp =l add %${p}_outer_ptr_${text(d)}, 32`)
|
||||
d = d + 1
|
||||
}
|
||||
emit(` %${p}_slotp =l add %${p}_fp, ${text(a2 * 8)}`)
|
||||
emit(` %${p}_val =l loadl %${p}_slotp`)
|
||||
s_write(a1, `%${p}_val`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (op == "put") {
|
||||
// mcode: put(val, slot, depth) — a2=slot, a3=depth
|
||||
v = s_read(a1)
|
||||
emit(` call $cell_rt_put_closure(l %ctx, l %fp, l ${v}, l ${text(a3)}, l ${text(a2)})`)
|
||||
depth = a3
|
||||
if (depth == 0) {
|
||||
s_write(a2, v)
|
||||
} else {
|
||||
p = fresh()
|
||||
emit(` %${p}_fp =l copy %fp`)
|
||||
d = 0
|
||||
while (d < depth) {
|
||||
emit(` %${p}_fn_p_${text(d)} =l sub %${p}_fp, 24`)
|
||||
emit(` %${p}_fn_${text(d)} =l loadl %${p}_fn_p_${text(d)}`)
|
||||
emit(` %${p}_fn_ptr_${text(d)} =l and %${p}_fn_${text(d)}, -8`)
|
||||
emit(` %${p}_outer_p_${text(d)} =l add %${p}_fn_ptr_${text(d)}, 40`)
|
||||
emit(` %${p}_outer_${text(d)} =l loadl %${p}_outer_p_${text(d)}`)
|
||||
emit(` %${p}_outer_ptr_${text(d)} =l and %${p}_outer_${text(d)}, -8`)
|
||||
emit(` %${p}_fp =l add %${p}_outer_ptr_${text(d)}, 32`)
|
||||
d = d + 1
|
||||
}
|
||||
emit(` %${p}_slotp =l add %${p}_fp, ${text(a2 * 8)}`)
|
||||
emit(` storel ${v}, %${p}_slotp`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -2401,8 +2755,52 @@ var qbe_emit = function(ir, qbe, export_name) {
|
||||
// --- Array push/pop [G] ---
|
||||
|
||||
if (op == "push") {
|
||||
lhs = s_read(a1)
|
||||
rhs = s_read(a2)
|
||||
p = fresh()
|
||||
emit(` %${p}_ptag =l and ${lhs}, 7`)
|
||||
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
|
||||
emit(` jnz %${p}_is_ptr, @${p}_arr_ptr, @${p}_slow`)
|
||||
emit(`@${p}_arr_ptr`)
|
||||
emit(` %${p}_arr_ptr =l and ${lhs}, -8`)
|
||||
emit(` %${p}_arr_hdr =l loadl %${p}_arr_ptr`)
|
||||
emit(`@${p}_arr_chase`)
|
||||
emit(` %${p}_arr_ty =l and %${p}_arr_hdr, 7`)
|
||||
emit(` %${p}_arr_is_fwd =w ceql %${p}_arr_ty, 7`)
|
||||
emit(` jnz %${p}_arr_is_fwd, @${p}_arr_follow, @${p}_arr_chk`)
|
||||
emit(`@${p}_arr_follow`)
|
||||
emit(` %${p}_arr_ptr =l shr %${p}_arr_hdr, 3`)
|
||||
emit(` %${p}_arr_hdr =l loadl %${p}_arr_ptr`)
|
||||
emit(` jmp @${p}_arr_chase`)
|
||||
emit(`@${p}_arr_chk`)
|
||||
emit(` %${p}_arr_is_array =w ceql %${p}_arr_ty, 0`)
|
||||
emit(` jnz %${p}_arr_is_array, @${p}_arr_stone_chk, @${p}_slow`)
|
||||
emit(`@${p}_arr_stone_chk`)
|
||||
emit(` %${p}_arr_stone =l and %${p}_arr_hdr, 8`)
|
||||
emit(` %${p}_arr_is_stone =w cnel %${p}_arr_stone, 0`)
|
||||
emit(` jnz %${p}_arr_is_stone, @${p}_slow, @${p}_lens`)
|
||||
emit(`@${p}_lens`)
|
||||
emit(` %${p}_len_p =l add %${p}_arr_ptr, 8`)
|
||||
emit(` %${p}_len_l =l loadl %${p}_len_p`)
|
||||
emit(` %${p}_len_w =w copy %${p}_len_l`)
|
||||
emit(` %${p}_cap_l =l shr %${p}_arr_hdr, 8`)
|
||||
emit(` %${p}_cap_w =w copy %${p}_cap_l`)
|
||||
emit(` %${p}_in_cap =w csltw %${p}_len_w, %${p}_cap_w`)
|
||||
emit(` jnz %${p}_in_cap, @${p}_store, @${p}_slow`)
|
||||
emit(`@${p}_store`)
|
||||
emit(` %${p}_idx_l =l extsw %${p}_len_w`)
|
||||
emit(` %${p}_idx_off =l shl %${p}_idx_l, 3`)
|
||||
emit(` %${p}_vals_p =l add %${p}_arr_ptr, 16`)
|
||||
emit(` %${p}_item_p =l add %${p}_vals_p, %${p}_idx_off`)
|
||||
emit(` storel ${rhs}, %${p}_item_p`)
|
||||
emit(` %${p}_next_len_w =w add %${p}_len_w, 1`)
|
||||
emit(` %${p}_next_len_l =l extsw %${p}_next_len_w`)
|
||||
emit(` storel %${p}_next_len_l, %${p}_len_p`)
|
||||
emit(` jmp @${p}_done`)
|
||||
emit(`@${p}_slow`)
|
||||
emit(` %fp =l call $__push_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)})`)
|
||||
emit_exc_check()
|
||||
emit(`@${p}_done`)
|
||||
continue
|
||||
}
|
||||
if (op == "pop") {
|
||||
|
||||
Reference in New Issue
Block a user