remove typed ops
This commit is contained in:
File diff suppressed because it is too large
Load Diff
28755
boot/fold.cm.mcode
28755
boot/fold.cm.mcode
File diff suppressed because one or more lines are too long
43234
boot/mcode.cm.mcode
43234
boot/mcode.cm.mcode
File diff suppressed because one or more lines are too long
44250
boot/parse.cm.mcode
44250
boot/parse.cm.mcode
File diff suppressed because one or more lines are too long
41246
boot/streamline.cm.mcode
41246
boot/streamline.cm.mcode
File diff suppressed because one or more lines are too long
11016
boot/tokenize.cm.mcode
11016
boot/tokenize.cm.mcode
File diff suppressed because one or more lines are too long
@@ -257,7 +257,7 @@ var run = function() {
|
||||
|
||||
annotation = ""
|
||||
if (kind == "rewritten") {
|
||||
if (search(o_instr[0], "_int") != null || search(o_instr[0], "_float") != null || search(o_instr[0], "_text") != null) {
|
||||
if (o_instr[0] == "concat" && m_instr[0] != "concat") {
|
||||
annotation = "(specialized)"
|
||||
} else {
|
||||
annotation = "(rewritten)"
|
||||
|
||||
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
|
||||
|
||||
88
slots.ce
88
slots.ce
@@ -24,70 +24,9 @@ var fmt_val = function(v) {
|
||||
return text(v)
|
||||
}
|
||||
|
||||
// Classify instruction operands as DEF or USE
|
||||
// Returns {defs: [operand_positions], uses: [operand_positions]}
|
||||
// Positions are 1-based indices into the instruction array
|
||||
var classify_operands = function(op) {
|
||||
// Binary ops: DEF=[1], USE=[2,3]
|
||||
if (op == "add" || op == "subtract" || op == "multiply" || op == "divide" ||
|
||||
op == "modulo" || op == "pow" || op == "remainder" ||
|
||||
op == "add_int" || op == "sub_int" || op == "mul_int" || op == "div_int" ||
|
||||
op == "mod_int" || op == "pow_int" || op == "rem_int" ||
|
||||
op == "add_float" || op == "sub_float" || op == "mul_float" || op == "div_float" ||
|
||||
op == "mod_float" || op == "pow_float" ||
|
||||
op == "eq" || op == "ne" || op == "lt" || op == "gt" || op == "le" || op == "ge" ||
|
||||
op == "eq_int" || op == "ne_int" || op == "lt_int" || op == "gt_int" ||
|
||||
op == "le_int" || op == "ge_int" ||
|
||||
op == "eq_float" || op == "ne_float" || op == "lt_float" || op == "gt_float" ||
|
||||
op == "le_float" || op == "ge_float" ||
|
||||
op == "eq_text" || op == "ne_text" || op == "lt_text" || op == "gt_text" ||
|
||||
op == "le_text" || op == "ge_text" ||
|
||||
op == "eq_bool" || op == "ne_bool" ||
|
||||
op == "concat" ||
|
||||
op == "bitand" || op == "bitor" || op == "bitxor" ||
|
||||
op == "shl" || op == "shr" || op == "ushr" ||
|
||||
op == "and" || op == "or" ||
|
||||
op == "is_identical") {
|
||||
return {defs: [1], uses: [2, 3]}
|
||||
}
|
||||
|
||||
// Unary ops: DEF=[1], USE=[2]
|
||||
if (op == "not" || op == "negate" || op == "neg_int" || op == "neg_float" ||
|
||||
op == "bitnot" || op == "typeof" || op == "length" ||
|
||||
op == "is_int" || op == "is_num" || op == "is_text" || op == "is_bool" ||
|
||||
op == "is_null" || op == "is_array" || op == "is_func" || op == "is_record" ||
|
||||
op == "is_stone" || op == "is_integer") {
|
||||
return {defs: [1], uses: [2]}
|
||||
}
|
||||
|
||||
// Constants: DEF=[1], USE=[]
|
||||
if (op == "int" || op == "true" || op == "false" || op == "null" || op == "access") {
|
||||
return {defs: [1], uses: []}
|
||||
}
|
||||
|
||||
if (op == "move") return {defs: [1], uses: [2]}
|
||||
if (op == "function") return {defs: [1], uses: []}
|
||||
if (op == "array") return {defs: [1], uses: []}
|
||||
if (op == "record") return {defs: [1], uses: []}
|
||||
if (op == "frame") return {defs: [1], uses: [2]}
|
||||
if (op == "setarg") return {defs: [], uses: [1, 3]}
|
||||
if (op == "invoke") return {defs: [2], uses: [1]}
|
||||
if (op == "tail_invoke" || op == "goinvoke") return {defs: [], uses: [1]}
|
||||
if (op == "load_field") return {defs: [1], uses: [2]}
|
||||
if (op == "store_field") return {defs: [], uses: [1, 3]}
|
||||
if (op == "load_index" || op == "load_dynamic") return {defs: [1], uses: [2, 3]}
|
||||
if (op == "store_index" || op == "store_dynamic") return {defs: [], uses: [1, 2, 3]}
|
||||
if (op == "push") return {defs: [], uses: [1, 2]}
|
||||
if (op == "pop") return {defs: [1], uses: [2]}
|
||||
if (op == "jump_true" || op == "jump_false" || op == "jump_null" || op == "jump_not_null") return {defs: [], uses: [1]}
|
||||
if (op == "jump") return {defs: [], uses: []}
|
||||
if (op == "return") return {defs: [], uses: [1]}
|
||||
if (op == "disrupt") return {defs: [], uses: []}
|
||||
if (op == "get") return {defs: [1], uses: []}
|
||||
if (op == "set_var") return {defs: [], uses: [1]}
|
||||
|
||||
return {defs: [], uses: []}
|
||||
}
|
||||
// DEF/USE functions — populated from streamline's log hooks
|
||||
var sl_get_defs = null
|
||||
var sl_get_uses = null
|
||||
|
||||
var run = function() {
|
||||
var filename = null
|
||||
@@ -137,9 +76,14 @@ var run = function() {
|
||||
sl_log = {
|
||||
passes: [],
|
||||
events: null,
|
||||
type_deltas: []
|
||||
type_deltas: [],
|
||||
request_def_use: true
|
||||
}
|
||||
streamline(mcode_copy, sl_log)
|
||||
if (sl_log.get_slot_defs != null) {
|
||||
sl_get_defs = sl_log.get_slot_defs
|
||||
sl_get_uses = sl_log.get_slot_uses
|
||||
}
|
||||
if (sl_log.type_deltas != null) {
|
||||
ti = 0
|
||||
while (ti < length(sl_log.type_deltas)) {
|
||||
@@ -181,7 +125,8 @@ var run = function() {
|
||||
var instr = null
|
||||
var op = null
|
||||
var n = 0
|
||||
var cls = null
|
||||
var def_positions = null
|
||||
var use_positions = null
|
||||
var di = 0
|
||||
var ui = 0
|
||||
var slot_num = null
|
||||
@@ -220,11 +165,12 @@ var run = function() {
|
||||
|
||||
op = instr[0]
|
||||
n = length(instr)
|
||||
cls = classify_operands(op)
|
||||
def_positions = sl_get_defs(instr)
|
||||
use_positions = sl_get_uses(instr)
|
||||
|
||||
di = 0
|
||||
while (di < length(cls.defs)) {
|
||||
operand_val = instr[cls.defs[di]]
|
||||
while (di < length(def_positions)) {
|
||||
operand_val = instr[def_positions[di]]
|
||||
if (is_number(operand_val)) {
|
||||
slot_num = text(operand_val)
|
||||
if (!defs[slot_num]) defs[slot_num] = 0
|
||||
@@ -239,8 +185,8 @@ var run = function() {
|
||||
}
|
||||
|
||||
ui = 0
|
||||
while (ui < length(cls.uses)) {
|
||||
operand_val = instr[cls.uses[ui]]
|
||||
while (ui < length(use_positions)) {
|
||||
operand_val = instr[use_positions[ui]]
|
||||
if (is_number(operand_val)) {
|
||||
slot_num = text(operand_val)
|
||||
if (!uses[slot_num]) uses[slot_num] = 0
|
||||
|
||||
154
source/mach.c
154
source/mach.c
@@ -214,34 +214,6 @@ typedef enum MachOpcode {
|
||||
MACH_CONCAT, /* R(A) = R(B) ++ R(C) — string concatenation */
|
||||
MACH_STONE_TEXT, /* stone(R(A)) — freeze mutable text before escape */
|
||||
|
||||
/* Typed integer comparisons (ABC) */
|
||||
MACH_EQ_INT, /* R(A) = (R(B) == R(C)) — int */
|
||||
MACH_NE_INT, /* R(A) = (R(B) != R(C)) — int */
|
||||
MACH_LT_INT, /* R(A) = (R(B) < R(C)) — int */
|
||||
MACH_LE_INT, /* R(A) = (R(B) <= R(C)) — int */
|
||||
MACH_GT_INT, /* R(A) = (R(B) > R(C)) — int */
|
||||
MACH_GE_INT, /* R(A) = (R(B) >= R(C)) — int */
|
||||
|
||||
/* Typed float comparisons (ABC) */
|
||||
MACH_EQ_FLOAT, /* R(A) = (R(B) == R(C)) — float */
|
||||
MACH_NE_FLOAT, /* R(A) = (R(B) != R(C)) — float */
|
||||
MACH_LT_FLOAT, /* R(A) = (R(B) < R(C)) — float */
|
||||
MACH_LE_FLOAT, /* R(A) = (R(B) <= R(C)) — float */
|
||||
MACH_GT_FLOAT, /* R(A) = (R(B) > R(C)) — float */
|
||||
MACH_GE_FLOAT, /* R(A) = (R(B) >= R(C)) — float */
|
||||
|
||||
/* Typed text comparisons (ABC) */
|
||||
MACH_EQ_TEXT, /* R(A) = (R(B) == R(C)) — text */
|
||||
MACH_NE_TEXT, /* R(A) = (R(B) != R(C)) — text */
|
||||
MACH_LT_TEXT, /* R(A) = (R(B) < R(C)) — text */
|
||||
MACH_LE_TEXT, /* R(A) = (R(B) <= R(C)) — text */
|
||||
MACH_GT_TEXT, /* R(A) = (R(B) > R(C)) — text */
|
||||
MACH_GE_TEXT, /* R(A) = (R(B) >= R(C)) — text */
|
||||
|
||||
/* Typed bool comparisons (ABC) */
|
||||
MACH_EQ_BOOL, /* R(A) = (R(B) == R(C)) — bool */
|
||||
MACH_NE_BOOL, /* R(A) = (R(B) != R(C)) — bool */
|
||||
|
||||
/* Special comparisons */
|
||||
MACH_IS_IDENTICAL, /* R(A) = (R(B) === R(C)) — identity check (ABC) */
|
||||
|
||||
@@ -374,26 +346,6 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
||||
/* Mcode-derived */
|
||||
[MACH_CONCAT] = "concat",
|
||||
[MACH_STONE_TEXT] = "stone_text",
|
||||
[MACH_EQ_INT] = "eq_int",
|
||||
[MACH_NE_INT] = "ne_int",
|
||||
[MACH_LT_INT] = "lt_int",
|
||||
[MACH_LE_INT] = "le_int",
|
||||
[MACH_GT_INT] = "gt_int",
|
||||
[MACH_GE_INT] = "ge_int",
|
||||
[MACH_EQ_FLOAT] = "eq_float",
|
||||
[MACH_NE_FLOAT] = "ne_float",
|
||||
[MACH_LT_FLOAT] = "lt_float",
|
||||
[MACH_LE_FLOAT] = "le_float",
|
||||
[MACH_GT_FLOAT] = "gt_float",
|
||||
[MACH_GE_FLOAT] = "ge_float",
|
||||
[MACH_EQ_TEXT] = "eq_text",
|
||||
[MACH_NE_TEXT] = "ne_text",
|
||||
[MACH_LT_TEXT] = "lt_text",
|
||||
[MACH_LE_TEXT] = "le_text",
|
||||
[MACH_GT_TEXT] = "gt_text",
|
||||
[MACH_GE_TEXT] = "ge_text",
|
||||
[MACH_EQ_BOOL] = "eq_bool",
|
||||
[MACH_NE_BOOL] = "ne_bool",
|
||||
[MACH_IS_IDENTICAL] = "is_identical",
|
||||
[MACH_IS_INT] = "is_int",
|
||||
[MACH_IS_NUM] = "is_num",
|
||||
@@ -1083,10 +1035,6 @@ static JSValue reg_vm_binop(JSContext *ctx, int op, JSValue a, JSValue b) {
|
||||
}
|
||||
}
|
||||
|
||||
/* String concat for ADD */
|
||||
if (op == MACH_ADD && mist_is_text(a) && mist_is_text(b))
|
||||
return JS_ConcatString(ctx, a, b);
|
||||
|
||||
/* Comparison ops allow mixed types — return false for mismatches */
|
||||
if (op >= MACH_EQ && op <= MACH_GE) {
|
||||
/* Fast path: identical values (chase pointers for forwarded objects) */
|
||||
@@ -1429,16 +1377,6 @@ vm_dispatch:
|
||||
DT(MACH_EQ_TOL), DT(MACH_NEQ_TOL),
|
||||
DT(MACH_NOP),
|
||||
DT(MACH_CONCAT), DT(MACH_STONE_TEXT),
|
||||
DT(MACH_EQ_INT), DT(MACH_NE_INT),
|
||||
DT(MACH_LT_INT), DT(MACH_LE_INT),
|
||||
DT(MACH_GT_INT), DT(MACH_GE_INT),
|
||||
DT(MACH_EQ_FLOAT), DT(MACH_NE_FLOAT),
|
||||
DT(MACH_LT_FLOAT), DT(MACH_LE_FLOAT),
|
||||
DT(MACH_GT_FLOAT), DT(MACH_GE_FLOAT),
|
||||
DT(MACH_EQ_TEXT), DT(MACH_NE_TEXT),
|
||||
DT(MACH_LT_TEXT), DT(MACH_LE_TEXT),
|
||||
DT(MACH_GT_TEXT), DT(MACH_GE_TEXT),
|
||||
DT(MACH_EQ_BOOL), DT(MACH_NE_BOOL),
|
||||
DT(MACH_IS_IDENTICAL),
|
||||
DT(MACH_IS_INT), DT(MACH_IS_NUM),
|
||||
DT(MACH_IS_TEXT), DT(MACH_IS_BOOL),
|
||||
@@ -2365,74 +2303,6 @@ vm_dispatch:
|
||||
stone_mutable_text(frame->slots[a]);
|
||||
VM_BREAK();
|
||||
|
||||
/* Typed integer comparisons */
|
||||
VM_CASE(MACH_EQ_INT):
|
||||
frame->slots[a] = JS_NewBool(ctx, JS_VALUE_GET_INT(frame->slots[b]) == JS_VALUE_GET_INT(frame->slots[c]));
|
||||
VM_BREAK();
|
||||
VM_CASE(MACH_NE_INT):
|
||||
frame->slots[a] = JS_NewBool(ctx, JS_VALUE_GET_INT(frame->slots[b]) != JS_VALUE_GET_INT(frame->slots[c]));
|
||||
VM_BREAK();
|
||||
VM_CASE(MACH_LT_INT):
|
||||
frame->slots[a] = JS_NewBool(ctx, JS_VALUE_GET_INT(frame->slots[b]) < JS_VALUE_GET_INT(frame->slots[c]));
|
||||
VM_BREAK();
|
||||
VM_CASE(MACH_LE_INT):
|
||||
frame->slots[a] = JS_NewBool(ctx, JS_VALUE_GET_INT(frame->slots[b]) <= JS_VALUE_GET_INT(frame->slots[c]));
|
||||
VM_BREAK();
|
||||
VM_CASE(MACH_GT_INT):
|
||||
frame->slots[a] = JS_NewBool(ctx, JS_VALUE_GET_INT(frame->slots[b]) > JS_VALUE_GET_INT(frame->slots[c]));
|
||||
VM_BREAK();
|
||||
VM_CASE(MACH_GE_INT):
|
||||
frame->slots[a] = JS_NewBool(ctx, JS_VALUE_GET_INT(frame->slots[b]) >= JS_VALUE_GET_INT(frame->slots[c]));
|
||||
VM_BREAK();
|
||||
|
||||
/* Typed float comparisons */
|
||||
VM_CASE(MACH_EQ_FLOAT): VM_CASE(MACH_NE_FLOAT):
|
||||
VM_CASE(MACH_LT_FLOAT): VM_CASE(MACH_LE_FLOAT):
|
||||
VM_CASE(MACH_GT_FLOAT): VM_CASE(MACH_GE_FLOAT): {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, frame->slots[b]);
|
||||
JS_ToFloat64(ctx, &db, frame->slots[c]);
|
||||
int r;
|
||||
switch (op) {
|
||||
case MACH_EQ_FLOAT: r = (da == db); break;
|
||||
case MACH_NE_FLOAT: r = (da != db); break;
|
||||
case MACH_LT_FLOAT: r = (da < db); break;
|
||||
case MACH_LE_FLOAT: r = (da <= db); break;
|
||||
case MACH_GT_FLOAT: r = (da > db); break;
|
||||
case MACH_GE_FLOAT: r = (da >= db); break;
|
||||
default: r = 0; break;
|
||||
}
|
||||
frame->slots[a] = JS_NewBool(ctx, r);
|
||||
VM_BREAK();
|
||||
}
|
||||
|
||||
/* Typed text comparisons */
|
||||
VM_CASE(MACH_EQ_TEXT): VM_CASE(MACH_NE_TEXT):
|
||||
VM_CASE(MACH_LT_TEXT): VM_CASE(MACH_LE_TEXT):
|
||||
VM_CASE(MACH_GT_TEXT): VM_CASE(MACH_GE_TEXT): {
|
||||
int cmp = js_string_compare_value(ctx, frame->slots[b], frame->slots[c], FALSE);
|
||||
int r;
|
||||
switch (op) {
|
||||
case MACH_EQ_TEXT: r = (cmp == 0); break;
|
||||
case MACH_NE_TEXT: r = (cmp != 0); break;
|
||||
case MACH_LT_TEXT: r = (cmp < 0); break;
|
||||
case MACH_LE_TEXT: r = (cmp <= 0); break;
|
||||
case MACH_GT_TEXT: r = (cmp > 0); break;
|
||||
case MACH_GE_TEXT: r = (cmp >= 0); break;
|
||||
default: r = 0; break;
|
||||
}
|
||||
frame->slots[a] = JS_NewBool(ctx, r);
|
||||
VM_BREAK();
|
||||
}
|
||||
|
||||
/* Typed bool comparisons */
|
||||
VM_CASE(MACH_EQ_BOOL):
|
||||
frame->slots[a] = JS_NewBool(ctx, JS_VALUE_GET_BOOL(frame->slots[b]) == JS_VALUE_GET_BOOL(frame->slots[c]));
|
||||
VM_BREAK();
|
||||
VM_CASE(MACH_NE_BOOL):
|
||||
frame->slots[a] = JS_NewBool(ctx, JS_VALUE_GET_BOOL(frame->slots[b]) != JS_VALUE_GET_BOOL(frame->slots[c]));
|
||||
VM_BREAK();
|
||||
|
||||
/* Identity check */
|
||||
VM_CASE(MACH_IS_IDENTICAL): {
|
||||
JSValue va = JS_IsPtr(frame->slots[b]) ? JS_MKPTR(chase(frame->slots[b])) : frame->slots[b];
|
||||
@@ -3105,30 +2975,6 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
|
||||
else if (strcmp(op, "le") == 0) { ABC3(MACH_LE); }
|
||||
else if (strcmp(op, "gt") == 0) { ABC3(MACH_GT); }
|
||||
else if (strcmp(op, "ge") == 0) { ABC3(MACH_GE); }
|
||||
/* Typed integer comparisons */
|
||||
else if (strcmp(op, "eq_int") == 0) { ABC3(MACH_EQ_INT); }
|
||||
else if (strcmp(op, "ne_int") == 0) { ABC3(MACH_NE_INT); }
|
||||
else if (strcmp(op, "lt_int") == 0) { ABC3(MACH_LT_INT); }
|
||||
else if (strcmp(op, "le_int") == 0) { ABC3(MACH_LE_INT); }
|
||||
else if (strcmp(op, "gt_int") == 0) { ABC3(MACH_GT_INT); }
|
||||
else if (strcmp(op, "ge_int") == 0) { ABC3(MACH_GE_INT); }
|
||||
/* Typed float comparisons */
|
||||
else if (strcmp(op, "eq_float") == 0) { ABC3(MACH_EQ_FLOAT); }
|
||||
else if (strcmp(op, "ne_float") == 0) { ABC3(MACH_NE_FLOAT); }
|
||||
else if (strcmp(op, "lt_float") == 0) { ABC3(MACH_LT_FLOAT); }
|
||||
else if (strcmp(op, "le_float") == 0) { ABC3(MACH_LE_FLOAT); }
|
||||
else if (strcmp(op, "gt_float") == 0) { ABC3(MACH_GT_FLOAT); }
|
||||
else if (strcmp(op, "ge_float") == 0) { ABC3(MACH_GE_FLOAT); }
|
||||
/* Typed text comparisons */
|
||||
else if (strcmp(op, "eq_text") == 0) { ABC3(MACH_EQ_TEXT); }
|
||||
else if (strcmp(op, "ne_text") == 0) { ABC3(MACH_NE_TEXT); }
|
||||
else if (strcmp(op, "lt_text") == 0) { ABC3(MACH_LT_TEXT); }
|
||||
else if (strcmp(op, "le_text") == 0) { ABC3(MACH_LE_TEXT); }
|
||||
else if (strcmp(op, "gt_text") == 0) { ABC3(MACH_GT_TEXT); }
|
||||
else if (strcmp(op, "ge_text") == 0) { ABC3(MACH_GE_TEXT); }
|
||||
/* Typed bool comparisons */
|
||||
else if (strcmp(op, "eq_bool") == 0) { ABC3(MACH_EQ_BOOL); }
|
||||
else if (strcmp(op, "ne_bool") == 0) { ABC3(MACH_NE_BOOL); }
|
||||
/* Special comparisons */
|
||||
else if (strcmp(op, "is_identical") == 0) { ABC3(MACH_IS_IDENTICAL); }
|
||||
else if (strcmp(op, "eq_tol") == 0) {
|
||||
|
||||
@@ -41,14 +41,8 @@ var streamline = function(ir, log) {
|
||||
max: true, min: true, pow: true
|
||||
}
|
||||
var bool_result_ops = {
|
||||
eq_int: true, ne_int: true, lt_int: true, gt_int: true,
|
||||
le_int: true, ge_int: true,
|
||||
eq_float: true, ne_float: true, lt_float: true, gt_float: true,
|
||||
le_float: true, ge_float: true,
|
||||
eq_text: true, ne_text: true, lt_text: true, gt_text: true,
|
||||
le_text: true, ge_text: true,
|
||||
eq_bool: true, ne_bool: true,
|
||||
eq_tol: true, ne_tol: true,
|
||||
eq: true, ne: true, lt: true, gt: true, le: true, ge: true,
|
||||
eq_tol: true, ne_tol: true, in: true,
|
||||
not: true, and: true, or: true,
|
||||
is_int: true, is_text: true, is_num: true,
|
||||
is_bool: true, is_null: true, is_identical: true,
|
||||
@@ -63,15 +57,10 @@ var streamline = function(ir, log) {
|
||||
|
||||
// simplify_algebra dispatch tables
|
||||
var self_true_ops = {
|
||||
eq_int: true, eq_float: true, eq_text: true, eq_bool: true,
|
||||
is_identical: true,
|
||||
le_int: true, le_float: true, le_text: true,
|
||||
ge_int: true, ge_float: true, ge_text: true
|
||||
eq: true, is_identical: true, le: true, ge: true
|
||||
}
|
||||
var self_false_ops = {
|
||||
ne_int: true, ne_float: true, ne_text: true, ne_bool: true,
|
||||
lt_int: true, lt_float: true, lt_text: true,
|
||||
gt_int: true, gt_float: true, gt_text: true
|
||||
ne: true, lt: true, gt: true
|
||||
}
|
||||
var no_clear_ops = {
|
||||
int: true, access: true, true: true, false: true, move: true, null: true,
|
||||
@@ -365,13 +354,6 @@ var streamline = function(ir, log) {
|
||||
load_index: [1, T_UNKNOWN], load_dynamic: [1, T_UNKNOWN],
|
||||
pop: [1, T_UNKNOWN], get: [1, T_UNKNOWN],
|
||||
invoke: [2, T_UNKNOWN], tail_invoke: [2, T_UNKNOWN],
|
||||
eq_int: [1, T_BOOL], ne_int: [1, T_BOOL], lt_int: [1, T_BOOL],
|
||||
gt_int: [1, T_BOOL], le_int: [1, T_BOOL], ge_int: [1, T_BOOL],
|
||||
eq_float: [1, T_BOOL], ne_float: [1, T_BOOL], lt_float: [1, T_BOOL],
|
||||
gt_float: [1, T_BOOL], le_float: [1, T_BOOL], ge_float: [1, T_BOOL],
|
||||
eq_text: [1, T_BOOL], ne_text: [1, T_BOOL], lt_text: [1, T_BOOL],
|
||||
gt_text: [1, T_BOOL], le_text: [1, T_BOOL], ge_text: [1, T_BOOL],
|
||||
eq_bool: [1, T_BOOL], ne_bool: [1, T_BOOL],
|
||||
eq_tol: [1, T_BOOL], ne_tol: [1, T_BOOL],
|
||||
not: [1, T_BOOL], and: [1, T_BOOL], or: [1, T_BOOL],
|
||||
is_int: [1, T_BOOL], is_text: [1, T_BOOL], is_num: [1, T_BOOL],
|
||||
@@ -1692,6 +1674,54 @@ var streamline = function(ir, log) {
|
||||
return result
|
||||
}
|
||||
|
||||
// DEF/USE classification: which instruction positions are definitions vs uses
|
||||
var slot_def_special = {
|
||||
get: [1], put: [], access: [1], int: [1], function: [1], regexp: [1],
|
||||
true: [1], false: [1], null: [1], record: [1], array: [1],
|
||||
invoke: [2], tail_invoke: [2], goinvoke: [],
|
||||
move: [1], load_field: [1], load_index: [1], load_dynamic: [1],
|
||||
pop: [1], frame: [1], goframe: [1],
|
||||
setarg: [], store_field: [], store_index: [], store_dynamic: [],
|
||||
push: [], set_var: [], stone_text: [],
|
||||
jump: [], jump_true: [], jump_false: [], jump_not_null: [],
|
||||
return: [], disrupt: []
|
||||
}
|
||||
|
||||
var slot_use_special = {
|
||||
get: [], put: [1], access: [], int: [], function: [], regexp: [],
|
||||
true: [], false: [], null: [], record: [], array: [],
|
||||
invoke: [1], tail_invoke: [1], goinvoke: [1],
|
||||
move: [2], load_field: [2], load_index: [2, 3], load_dynamic: [2, 3],
|
||||
pop: [2], frame: [2], goframe: [2],
|
||||
setarg: [1, 3], store_field: [1, 3], store_index: [1, 2, 3],
|
||||
store_dynamic: [1, 2, 3],
|
||||
push: [1, 2], set_var: [1], stone_text: [1],
|
||||
jump: [], jump_true: [1], jump_false: [1], jump_not_null: [1],
|
||||
return: [1], disrupt: []
|
||||
}
|
||||
|
||||
var get_slot_defs = function(instr) {
|
||||
var special = slot_def_special[instr[0]]
|
||||
if (special != null) return special
|
||||
return [1]
|
||||
}
|
||||
|
||||
var get_slot_uses = function(instr) {
|
||||
var special = slot_use_special[instr[0]]
|
||||
var result = null
|
||||
var j = 0
|
||||
var limit = 0
|
||||
if (special != null) return special
|
||||
result = []
|
||||
limit = length(instr) - 2
|
||||
j = 2
|
||||
while (j < limit) {
|
||||
if (is_number(instr[j])) result[] = j
|
||||
j = j + 1
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
var compress_one_fn = function(func, captured_slots) {
|
||||
var instructions = func.instructions
|
||||
var nr_slots = func.nr_slots
|
||||
@@ -2648,6 +2678,14 @@ var streamline = function(ir, log) {
|
||||
// Compress slots across all functions (must run after per-function passes)
|
||||
compress_slots(ir)
|
||||
|
||||
// Expose DEF/USE functions via log if requested
|
||||
if (log != null) {
|
||||
if (log.request_def_use) {
|
||||
log.get_slot_defs = get_slot_defs
|
||||
log.get_slot_uses = get_slot_uses
|
||||
}
|
||||
}
|
||||
|
||||
return ir
|
||||
}
|
||||
|
||||
|
||||
16
vm_suite.ce
16
vm_suite.ce
@@ -2761,6 +2761,22 @@ run("modulo floats", function() {
|
||||
if (result < 1.4 || result > 1.6) fail("modulo floats failed")
|
||||
})
|
||||
|
||||
run("remainder float basic", function() {
|
||||
if (remainder(5.5, 2.5) != 0.5) fail("remainder 5.5 % 2.5 failed")
|
||||
})
|
||||
|
||||
run("modulo float basic", function() {
|
||||
if (modulo(5.5, 2.5) != 0.5) fail("modulo 5.5 % 2.5 failed")
|
||||
})
|
||||
|
||||
run("remainder float negative", function() {
|
||||
if (remainder(-5.5, 2.5) != -0.5) fail("remainder -5.5 % 2.5 failed")
|
||||
})
|
||||
|
||||
run("modulo float negative", function() {
|
||||
if (modulo(-5.5, 2.5) != 2.0) fail("modulo -5.5 % 2.5 failed")
|
||||
})
|
||||
|
||||
// ============================================================================
|
||||
// MIN AND MAX FUNCTIONS
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user