remove typed ops
This commit is contained in:
317
mcode.cm
317
mcode.cm
@@ -354,28 +354,29 @@ var mcode = function(ast) {
|
||||
// emit_add_decomposed: emit type-dispatched add (text → concat, num → add)
|
||||
// reads _bp_dest, _bp_left, _bp_right, _bp_ln, _bp_rn from closure
|
||||
var emit_add_decomposed = function() {
|
||||
if (is_known_text(_bp_ln) && is_known_text(_bp_rn)) {
|
||||
var left_is_num = is_known_number(_bp_ln) || slot_is_num(_bp_left)
|
||||
var left_is_text = is_known_text(_bp_ln) || slot_is_text(_bp_left)
|
||||
var right_is_num = is_known_number(_bp_rn) || slot_is_num(_bp_right)
|
||||
var right_is_text = is_known_text(_bp_rn) || slot_is_text(_bp_right)
|
||||
|
||||
// Both known text → concat
|
||||
if (left_is_text && right_is_text) {
|
||||
emit_3("concat", _bp_dest, _bp_left, _bp_right)
|
||||
mark_slot(_bp_dest, "text")
|
||||
return null
|
||||
}
|
||||
if (is_known_number(_bp_ln) && is_known_number(_bp_rn)) {
|
||||
// Both known number → add
|
||||
if (left_is_num && right_is_num) {
|
||||
emit_3("add", _bp_dest, _bp_left, _bp_right)
|
||||
mark_slot(_bp_dest, "num")
|
||||
return null
|
||||
}
|
||||
// If either operand is a known number (AST or slot), concat is impossible
|
||||
if (is_known_number(_bp_ln) || is_known_number(_bp_rn)
|
||||
|| slot_is_num(_bp_left) || slot_is_num(_bp_right)) {
|
||||
// One known number, other unknown → emit_numeric_binop (guard on unknown side)
|
||||
if (left_is_num || right_is_num) {
|
||||
emit_numeric_binop("add")
|
||||
mark_slot(_bp_dest, "num")
|
||||
return null
|
||||
}
|
||||
if (slot_is_text(_bp_left) && slot_is_text(_bp_right)) {
|
||||
emit_3("concat", _bp_dest, _bp_left, _bp_right)
|
||||
mark_slot(_bp_dest, "text")
|
||||
return null
|
||||
}
|
||||
// Unknown types: emit full dispatch
|
||||
var t0 = alloc_slot()
|
||||
var t1 = alloc_slot()
|
||||
@@ -410,8 +411,8 @@ var mcode = function(ast) {
|
||||
// emit_numeric_binop: emit type-guarded numeric binary op
|
||||
// reads _bp_dest, _bp_left, _bp_right, _bp_ln, _bp_rn from closure
|
||||
var emit_numeric_binop = function(op_str) {
|
||||
if ((is_known_number(_bp_ln) && is_known_number(_bp_rn))
|
||||
|| (slot_is_num(_bp_left) && slot_is_num(_bp_right))) {
|
||||
if ((is_known_number(_bp_ln) || slot_is_num(_bp_left))
|
||||
&& (is_known_number(_bp_rn) || slot_is_num(_bp_right))) {
|
||||
emit_3(op_str, _bp_dest, _bp_left, _bp_right)
|
||||
mark_slot(_bp_dest, "num")
|
||||
return null
|
||||
@@ -435,239 +436,21 @@ var mcode = function(ast) {
|
||||
return null
|
||||
}
|
||||
|
||||
// emit_eq_decomposed: identical -> int -> float -> text -> null -> bool -> mismatch(false)
|
||||
// reads _bp_dest, _bp_left, _bp_right from closure
|
||||
// emit_eq_decomposed: VM eq handles all types (int fast path, text memcmp, identity, mixed→false)
|
||||
var emit_eq_decomposed = function() {
|
||||
var dest = _bp_dest
|
||||
var left = _bp_left
|
||||
var right = _bp_right
|
||||
var t0 = 0
|
||||
var t1 = 0
|
||||
|
||||
// Known-num fast path
|
||||
if ((is_known_number(_bp_ln) || slot_is_num(left))
|
||||
&& (is_known_number(_bp_rn) || slot_is_num(right))) {
|
||||
emit_3("eq_float", dest, left, right)
|
||||
return null
|
||||
}
|
||||
// Known-text fast path
|
||||
if ((is_known_text(_bp_ln) || slot_is_text(left))
|
||||
&& (is_known_text(_bp_rn) || slot_is_text(right))) {
|
||||
emit_3("eq_text", dest, left, right)
|
||||
return null
|
||||
}
|
||||
|
||||
var done = gen_label("eq_done")
|
||||
var not_int = gen_label("eq_ni")
|
||||
var not_num = gen_label("eq_nn")
|
||||
var not_text = gen_label("eq_nt")
|
||||
var not_null = gen_label("eq_nnl")
|
||||
var not_bool = gen_label("eq_nb")
|
||||
|
||||
// Identical check
|
||||
emit_3("is_identical", dest, left, right)
|
||||
emit_jump_cond("jump_true", dest, done)
|
||||
|
||||
// Int path
|
||||
t0 = alloc_slot()
|
||||
emit_2("is_int", t0, left)
|
||||
emit_jump_cond("jump_false", t0, not_int)
|
||||
t1 = alloc_slot()
|
||||
emit_2("is_int", t1, right)
|
||||
emit_jump_cond("jump_false", t1, not_int)
|
||||
emit_3("eq_int", dest, left, right)
|
||||
emit_jump(done)
|
||||
|
||||
// Float path
|
||||
emit_label(not_int)
|
||||
emit_2("is_num", t0, left)
|
||||
emit_jump_cond("jump_false", t0, not_num)
|
||||
emit_2("is_num", t1, right)
|
||||
emit_jump_cond("jump_false", t1, not_num)
|
||||
emit_3("eq_float", dest, left, right)
|
||||
emit_jump(done)
|
||||
|
||||
// Text path
|
||||
emit_label(not_num)
|
||||
emit_2("is_text", t0, left)
|
||||
emit_jump_cond("jump_false", t0, not_text)
|
||||
emit_2("is_text", t1, right)
|
||||
emit_jump_cond("jump_false", t1, not_text)
|
||||
emit_3("eq_text", dest, left, right)
|
||||
emit_jump(done)
|
||||
|
||||
// Null path
|
||||
emit_label(not_text)
|
||||
emit_2("is_null", t0, left)
|
||||
emit_jump_cond("jump_false", t0, not_null)
|
||||
emit_2("is_null", t1, right)
|
||||
emit_jump_cond("jump_false", t1, not_null)
|
||||
emit_1("true", dest)
|
||||
emit_jump(done)
|
||||
|
||||
// Bool path
|
||||
emit_label(not_null)
|
||||
emit_2("is_bool", t0, left)
|
||||
emit_jump_cond("jump_false", t0, not_bool)
|
||||
emit_2("is_bool", t1, right)
|
||||
emit_jump_cond("jump_false", t1, not_bool)
|
||||
emit_3("eq_bool", dest, left, right)
|
||||
emit_jump(done)
|
||||
|
||||
// Mismatch -> false
|
||||
emit_label(not_bool)
|
||||
emit_1("false", dest)
|
||||
emit_label(done)
|
||||
emit_3("eq", _bp_dest, _bp_left, _bp_right)
|
||||
return null
|
||||
}
|
||||
|
||||
// emit_ne_decomposed: identical -> int -> float -> text -> null -> bool -> mismatch(true)
|
||||
// reads _bp_dest, _bp_left, _bp_right from closure
|
||||
// emit_ne_decomposed: VM ne handles all types (int fast path, text memcmp, identity, mixed→true)
|
||||
var emit_ne_decomposed = function() {
|
||||
var dest = _bp_dest
|
||||
var left = _bp_left
|
||||
var right = _bp_right
|
||||
var t0 = 0
|
||||
var t1 = 0
|
||||
|
||||
// Known-num fast path
|
||||
if ((is_known_number(_bp_ln) || slot_is_num(left))
|
||||
&& (is_known_number(_bp_rn) || slot_is_num(right))) {
|
||||
emit_3("ne_float", dest, left, right)
|
||||
return null
|
||||
}
|
||||
// Known-text fast path
|
||||
if ((is_known_text(_bp_ln) || slot_is_text(left))
|
||||
&& (is_known_text(_bp_rn) || slot_is_text(right))) {
|
||||
emit_3("ne_text", dest, left, right)
|
||||
return null
|
||||
}
|
||||
|
||||
var done = gen_label("ne_done")
|
||||
var not_ident = gen_label("ne_nid")
|
||||
var not_int = gen_label("ne_ni")
|
||||
var not_num = gen_label("ne_nn")
|
||||
var not_text = gen_label("ne_nt")
|
||||
var not_null = gen_label("ne_nnl")
|
||||
var not_bool = gen_label("ne_nb")
|
||||
|
||||
// Identical -> false
|
||||
emit_3("is_identical", dest, left, right)
|
||||
emit_jump_cond("jump_true", dest, not_ident)
|
||||
// If jump_true doesn't fire, dest already holds false, continue to checks
|
||||
emit_jump(not_int)
|
||||
|
||||
emit_label(not_ident)
|
||||
emit_1("false", dest)
|
||||
emit_jump(done)
|
||||
|
||||
// Int path
|
||||
emit_label(not_int)
|
||||
t0 = alloc_slot()
|
||||
emit_2("is_int", t0, left)
|
||||
emit_jump_cond("jump_false", t0, not_num)
|
||||
t1 = alloc_slot()
|
||||
emit_2("is_int", t1, right)
|
||||
emit_jump_cond("jump_false", t1, not_num)
|
||||
emit_3("ne_int", dest, left, right)
|
||||
emit_jump(done)
|
||||
|
||||
// Float path
|
||||
emit_label(not_num)
|
||||
emit_2("is_num", t0, left)
|
||||
emit_jump_cond("jump_false", t0, not_text)
|
||||
emit_2("is_num", t1, right)
|
||||
emit_jump_cond("jump_false", t1, not_text)
|
||||
emit_3("ne_float", dest, left, right)
|
||||
emit_jump(done)
|
||||
|
||||
// Text path
|
||||
emit_label(not_text)
|
||||
emit_2("is_text", t0, left)
|
||||
emit_jump_cond("jump_false", t0, not_null)
|
||||
emit_2("is_text", t1, right)
|
||||
emit_jump_cond("jump_false", t1, not_null)
|
||||
emit_3("ne_text", dest, left, right)
|
||||
emit_jump(done)
|
||||
|
||||
// Null path
|
||||
emit_label(not_null)
|
||||
emit_2("is_null", t0, left)
|
||||
emit_jump_cond("jump_false", t0, not_bool)
|
||||
emit_2("is_null", t1, right)
|
||||
emit_jump_cond("jump_false", t1, not_bool)
|
||||
emit_1("false", dest)
|
||||
emit_jump(done)
|
||||
|
||||
// Bool path
|
||||
var mismatch = gen_label("ne_mis")
|
||||
emit_label(not_bool)
|
||||
emit_2("is_bool", t0, left)
|
||||
emit_jump_cond("jump_false", t0, mismatch)
|
||||
emit_2("is_bool", t1, right)
|
||||
emit_jump_cond("jump_false", t1, mismatch)
|
||||
emit_3("ne_bool", dest, left, right)
|
||||
emit_jump(done)
|
||||
|
||||
// Mismatch -> true (ne of different types is true)
|
||||
emit_label(mismatch)
|
||||
emit_1("true", dest)
|
||||
emit_label(done)
|
||||
emit_3("ne", _bp_dest, _bp_left, _bp_right)
|
||||
return null
|
||||
}
|
||||
|
||||
// emit_relational: int -> float -> text -> disrupt
|
||||
// reads _bp_dest, _bp_left, _bp_right, _bp_ln, _bp_rn from closure
|
||||
var emit_relational = function(poly_op, int_op, float_op, text_op) {
|
||||
var dest = _bp_dest
|
||||
var left = _bp_left
|
||||
var right = _bp_right
|
||||
var t0 = 0
|
||||
var t1 = 0
|
||||
var left_is_num = is_known_number(_bp_ln) || slot_is_num(left)
|
||||
var left_is_text = is_known_text(_bp_ln) || slot_is_text(left)
|
||||
var right_is_num = is_known_number(_bp_rn) || slot_is_num(right)
|
||||
var right_is_text = is_known_text(_bp_rn) || slot_is_text(right)
|
||||
var not_num = null
|
||||
var done = null
|
||||
var err = null
|
||||
|
||||
// Both known number
|
||||
if (left_is_num && right_is_num) {
|
||||
emit_3(poly_op, dest, left, right)
|
||||
return null
|
||||
}
|
||||
// Both known text
|
||||
if (left_is_text && right_is_text) {
|
||||
emit_3(text_op, dest, left, right)
|
||||
return null
|
||||
}
|
||||
|
||||
not_num = gen_label("rel_nn")
|
||||
done = gen_label("rel_done")
|
||||
err = gen_label("rel_err")
|
||||
|
||||
t0 = alloc_slot()
|
||||
emit_2("is_num", t0, left)
|
||||
emit_jump_cond("jump_false", t0, not_num)
|
||||
t1 = alloc_slot()
|
||||
emit_2("is_num", t1, right)
|
||||
emit_jump_cond("jump_false", t1, not_num)
|
||||
emit_3(poly_op, dest, left, right)
|
||||
emit_jump(done)
|
||||
|
||||
emit_label(not_num)
|
||||
emit_2("is_text", t0, left)
|
||||
emit_jump_cond("jump_false", t0, err)
|
||||
emit_2("is_text", t1, right)
|
||||
emit_jump_cond("jump_false", t1, err)
|
||||
emit_3(text_op, dest, left, right)
|
||||
emit_jump(done)
|
||||
|
||||
emit_label(err)
|
||||
emit_log_error("cannot compare with '" + _bp_op_sym + "': operands must be same type")
|
||||
emit_0("disrupt")
|
||||
emit_label(done)
|
||||
// emit_relational: VM lt/le/gt/ge handle numbers and text, disrupt on mismatch
|
||||
var emit_relational = function(op_str) {
|
||||
emit_3(op_str, _bp_dest, _bp_left, _bp_right)
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -696,14 +479,7 @@ var mcode = function(ast) {
|
||||
|
||||
// Central router: maps op string to decomposition helper
|
||||
// Sets _bp_* closure vars then calls helper with reduced args
|
||||
var relational_ops = {
|
||||
lt: ["lt", "lt_int", "lt_float", "lt_text"],
|
||||
le: ["le", "le_int", "le_float", "le_text"],
|
||||
gt: ["gt", "gt_int", "gt_float", "gt_text"],
|
||||
ge: ["ge", "ge_int", "ge_float", "ge_text"]
|
||||
}
|
||||
var emit_binop = function(op_str, dest, left, right) {
|
||||
var rel = null
|
||||
_bp_dest = dest
|
||||
_bp_left = left
|
||||
_bp_right = right
|
||||
@@ -714,18 +490,15 @@ var mcode = function(ast) {
|
||||
emit_eq_decomposed()
|
||||
} else if (op_str == "ne") {
|
||||
emit_ne_decomposed()
|
||||
} else if (op_str == "lt" || op_str == "le" || op_str == "gt" || op_str == "ge") {
|
||||
emit_relational(op_str)
|
||||
} else if (op_str == "subtract" || op_str == "multiply" ||
|
||||
op_str == "divide" || op_str == "modulo" || op_str == "remainder" ||
|
||||
op_str == "pow") {
|
||||
emit_numeric_binop(op_str)
|
||||
} else {
|
||||
rel = relational_ops[op_str]
|
||||
if (rel != null) {
|
||||
emit_relational(rel[0], rel[1], rel[2], rel[3])
|
||||
} else if (op_str == "subtract" || op_str == "multiply" ||
|
||||
op_str == "divide" || op_str == "modulo" || op_str == "remainder" ||
|
||||
op_str == "pow") {
|
||||
emit_numeric_binop(op_str)
|
||||
} else {
|
||||
// Passthrough for bitwise, in, etc.
|
||||
emit_3(op_str, dest, left, right)
|
||||
}
|
||||
// Passthrough for bitwise, in, etc.
|
||||
emit_3(op_str, dest, left, right)
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -1103,20 +876,20 @@ var mcode = function(ast) {
|
||||
emit_1("null", null_s)
|
||||
emit_label(loop_label)
|
||||
if (forward) {
|
||||
emit_3("lt_int", check, i, len)
|
||||
emit_3("lt", check, i, len)
|
||||
} else {
|
||||
emit_3("ge_int", check, i, zero)
|
||||
emit_3("ge", check, i, zero)
|
||||
}
|
||||
emit_jump_cond("jump_false", check, done_label)
|
||||
emit_3("load_index", item, arr_slot, i)
|
||||
emit_3("eq_int", arity_is_zero, fn_arity, zero)
|
||||
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_int", arity_is_one, fn_arity, one)
|
||||
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)
|
||||
@@ -1164,17 +937,17 @@ var mcode = function(ast) {
|
||||
emit_1("null", null_s)
|
||||
emit_2("length", fn_arity, fn_slot)
|
||||
emit_label(loop_label)
|
||||
emit_3("lt_int", check, i, len)
|
||||
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_int", arity_is_zero, fn_arity, zero)
|
||||
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_int", arity_is_one, fn_arity, one)
|
||||
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)
|
||||
@@ -1221,10 +994,10 @@ var mcode = function(ast) {
|
||||
emit_1("null", null_s)
|
||||
emit_2("length", fn_arity, fn_slot)
|
||||
emit_label(loop_label)
|
||||
emit_3("lt_int", check, i, len)
|
||||
emit_3("lt", check, i, len)
|
||||
emit_jump_cond("jump_false", check, ret_true)
|
||||
emit_3("load_index", item, arr_slot, i)
|
||||
emit_3("eq_int", arity_is_zero, fn_arity, zero)
|
||||
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)
|
||||
@@ -1274,10 +1047,10 @@ var mcode = function(ast) {
|
||||
emit_1("null", null_s)
|
||||
emit_2("length", fn_arity, fn_slot)
|
||||
emit_label(loop_label)
|
||||
emit_3("lt_int", check, i, len)
|
||||
emit_3("lt", check, i, len)
|
||||
emit_jump_cond("jump_false", check, ret_false)
|
||||
emit_3("load_index", item, arr_slot, i)
|
||||
emit_3("eq_int", arity_is_zero, fn_arity, zero)
|
||||
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)
|
||||
@@ -1330,17 +1103,17 @@ var mcode = function(ast) {
|
||||
emit_1("null", null_s)
|
||||
emit_2("length", fn_arity, fn_slot)
|
||||
emit_label(loop_label)
|
||||
emit_3("lt_int", check, i, len)
|
||||
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_int", arity_is_zero, fn_arity, zero)
|
||||
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_int", arity_is_one, fn_arity, one)
|
||||
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)
|
||||
@@ -1395,7 +1168,7 @@ var mcode = function(ast) {
|
||||
if (nargs == 2) {
|
||||
null_label = gen_label("reduce_null")
|
||||
d1 = gen_label("reduce_d1")
|
||||
emit_3("lt_int", check, zero, len)
|
||||
emit_3("lt", check, zero, len)
|
||||
emit_jump_cond("jump_false", check, null_label)
|
||||
emit_3("load_index", acc, arr_slot, zero)
|
||||
emit_2("move", i, one)
|
||||
@@ -1414,7 +1187,7 @@ var mcode = function(ast) {
|
||||
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_3("lt", check, zero, len)
|
||||
emit_jump_cond("jump_false", check, null_label)
|
||||
emit_3("load_index", acc, arr_slot, zero)
|
||||
emit_2("move", i, one)
|
||||
@@ -1446,7 +1219,7 @@ var mcode = function(ast) {
|
||||
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_3("lt", check, zero, len)
|
||||
emit_jump_cond("jump_false", check, null_label)
|
||||
emit_jump_cond("jump_true", rev_slot, no_init_rev)
|
||||
// No initial, forward
|
||||
|
||||
Reference in New Issue
Block a user