optimize
This commit is contained in:
105
mcode.cm
105
mcode.cm
@@ -88,6 +88,7 @@ var mcode = function(ast) {
|
||||
var s_cur_col = 0
|
||||
var s_filename = null
|
||||
var s_has_disruption = false
|
||||
var s_slot_types = {}
|
||||
|
||||
// Shared closure vars for binop helpers (avoids >4 param functions)
|
||||
var _bp_dest = 0
|
||||
@@ -116,7 +117,8 @@ var mcode = function(ast) {
|
||||
intrinsic_cache: s_intrinsic_cache,
|
||||
cur_line: s_cur_line,
|
||||
cur_col: s_cur_col,
|
||||
has_disruption: s_has_disruption
|
||||
has_disruption: s_has_disruption,
|
||||
slot_types: s_slot_types
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +140,7 @@ var mcode = function(ast) {
|
||||
s_cur_line = saved.cur_line
|
||||
s_cur_col = saved.cur_col
|
||||
s_has_disruption = saved.has_disruption
|
||||
s_slot_types = saved.slot_types
|
||||
}
|
||||
|
||||
// Slot allocation
|
||||
@@ -330,20 +333,47 @@ var mcode = function(ast) {
|
||||
return node.kind == "null"
|
||||
}
|
||||
|
||||
// Slot-type tracking helpers
|
||||
var slot_is_num = function(slot) {
|
||||
var t = s_slot_types[text(slot)]
|
||||
return t == "num" || t == "int"
|
||||
}
|
||||
|
||||
var slot_is_int = function(slot) {
|
||||
return s_slot_types[text(slot)] == "int"
|
||||
}
|
||||
|
||||
var slot_is_text = function(slot) {
|
||||
return s_slot_types[text(slot)] == "text"
|
||||
}
|
||||
|
||||
var mark_slot = function(slot, typ) {
|
||||
s_slot_types[text(slot)] = typ
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
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)) {
|
||||
emit_3("add", _bp_dest, _bp_left, _bp_right)
|
||||
mark_slot(_bp_dest, "num")
|
||||
return null
|
||||
}
|
||||
// If either operand is a known number, concat is impossible
|
||||
if (is_known_number(_bp_ln) || is_known_number(_bp_rn)) {
|
||||
// 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)) {
|
||||
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
|
||||
@@ -380,8 +410,10 @@ 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)) {
|
||||
if ((is_known_number(_bp_ln) && is_known_number(_bp_rn))
|
||||
|| (slot_is_num(_bp_left) && slot_is_num(_bp_right))) {
|
||||
emit_3(op_str, _bp_dest, _bp_left, _bp_right)
|
||||
mark_slot(_bp_dest, "num")
|
||||
return null
|
||||
}
|
||||
var t0 = alloc_slot()
|
||||
@@ -399,6 +431,7 @@ var mcode = function(ast) {
|
||||
emit_log_error("cannot apply '" + _bp_op_sym + "': operands must be numbers")
|
||||
emit_0("disrupt")
|
||||
emit_label(done)
|
||||
mark_slot(_bp_dest, "num")
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -410,6 +443,26 @@ var mcode = function(ast) {
|
||||
var right = _bp_right
|
||||
var t0 = 0
|
||||
var t1 = 0
|
||||
|
||||
// Known-int fast path
|
||||
if ((is_known_int(_bp_ln) || slot_is_int(left))
|
||||
&& (is_known_int(_bp_rn) || slot_is_int(right))) {
|
||||
emit_3("eq_int", dest, left, right)
|
||||
return null
|
||||
}
|
||||
// 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")
|
||||
@@ -482,6 +535,26 @@ var mcode = function(ast) {
|
||||
var right = _bp_right
|
||||
var t0 = 0
|
||||
var t1 = 0
|
||||
|
||||
// Known-int fast path
|
||||
if ((is_known_int(_bp_ln) || slot_is_int(left))
|
||||
&& (is_known_int(_bp_rn) || slot_is_int(right))) {
|
||||
emit_3("ne_int", dest, left, right)
|
||||
return null
|
||||
}
|
||||
// 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")
|
||||
@@ -563,12 +636,12 @@ var mcode = function(ast) {
|
||||
var right = _bp_right
|
||||
var t0 = 0
|
||||
var t1 = 0
|
||||
var left_is_int = is_known_int(_bp_ln)
|
||||
var left_is_num = is_known_number(_bp_ln)
|
||||
var left_is_text = is_known_text(_bp_ln)
|
||||
var right_is_int = is_known_int(_bp_rn)
|
||||
var right_is_num = is_known_number(_bp_rn)
|
||||
var right_is_text = is_known_text(_bp_rn)
|
||||
var left_is_int = is_known_int(_bp_ln) || slot_is_int(left)
|
||||
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_int = is_known_int(_bp_rn) || slot_is_int(right)
|
||||
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
|
||||
@@ -619,8 +692,9 @@ var mcode = function(ast) {
|
||||
|
||||
// emit_neg_decomposed: emit type-guarded negate
|
||||
var emit_neg_decomposed = function(dest, src, src_node) {
|
||||
if (is_known_number(src_node)) {
|
||||
if (is_known_number(src_node) || slot_is_num(src)) {
|
||||
emit_2("negate", dest, src)
|
||||
mark_slot(dest, "num")
|
||||
return null
|
||||
}
|
||||
var t0 = alloc_slot()
|
||||
@@ -635,6 +709,7 @@ var mcode = function(ast) {
|
||||
emit_log_error("cannot negate: operand must be a number")
|
||||
emit_0("disrupt")
|
||||
emit_label(done)
|
||||
mark_slot(dest, "num")
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -1794,6 +1869,7 @@ var mcode = function(ast) {
|
||||
if (kind == "number") {
|
||||
slot = target >= 0 ? target : alloc_slot()
|
||||
emit_const_num(slot, expr.number)
|
||||
mark_slot(slot, is_integer(expr.number) ? "int" : "num")
|
||||
return slot
|
||||
}
|
||||
if (kind == "text") {
|
||||
@@ -1803,6 +1879,7 @@ var mcode = function(ast) {
|
||||
val = ""
|
||||
}
|
||||
emit_const_str(slot, val)
|
||||
mark_slot(slot, "text")
|
||||
return slot
|
||||
}
|
||||
// Template literal
|
||||
@@ -1839,6 +1916,7 @@ var mcode = function(ast) {
|
||||
// Call format(fmt_str, array)
|
||||
result_slot = target >= 0 ? target : alloc_slot()
|
||||
emit_call(result_slot, fmt_func_slot, [fmt_str_slot, arr_slot])
|
||||
mark_slot(result_slot, "text")
|
||||
return result_slot
|
||||
}
|
||||
if (kind == "regexp") {
|
||||
@@ -1857,16 +1935,19 @@ var mcode = function(ast) {
|
||||
if (kind == "true") {
|
||||
slot = target >= 0 ? target : alloc_slot()
|
||||
emit_const_bool(slot, true)
|
||||
mark_slot(slot, "bool")
|
||||
return slot
|
||||
}
|
||||
if (kind == "false") {
|
||||
slot = target >= 0 ? target : alloc_slot()
|
||||
emit_const_bool(slot, false)
|
||||
mark_slot(slot, "bool")
|
||||
return slot
|
||||
}
|
||||
if (kind == "null") {
|
||||
slot = target >= 0 ? target : alloc_slot()
|
||||
emit_const_null(slot)
|
||||
mark_slot(slot, null)
|
||||
return slot
|
||||
}
|
||||
if (kind == "this") {
|
||||
@@ -2760,6 +2841,7 @@ var mcode = function(ast) {
|
||||
s_instructions = []
|
||||
s_vars = []
|
||||
s_intrinsic_cache = []
|
||||
s_slot_types = {}
|
||||
s_loop_break = null
|
||||
s_loop_continue = null
|
||||
s_label_map = {}
|
||||
@@ -2951,6 +3033,7 @@ var mcode = function(ast) {
|
||||
s_max_slot = 1
|
||||
s_label_counter = 0
|
||||
s_func_counter = 0
|
||||
s_slot_types = {}
|
||||
s_loop_break = null
|
||||
s_loop_continue = null
|
||||
s_label_map = {}
|
||||
|
||||
@@ -141,6 +141,13 @@ var streamline = function(ir, log) {
|
||||
}
|
||||
|
||||
// track_types reuses write_rules table; move handled specially
|
||||
// Ops safe to narrow from T_NUM to T_INT when both operands are T_INT.
|
||||
// Excludes divide (int/int can produce float) and pow (int**neg produces float).
|
||||
var int_narrowable_ops = {
|
||||
add: true, subtract: true, multiply: true,
|
||||
remainder: true, modulo: true, max: true, min: true
|
||||
}
|
||||
|
||||
var track_types = function(slot_types, instr) {
|
||||
var op = instr[0]
|
||||
var rule = null
|
||||
@@ -157,6 +164,13 @@ var streamline = function(ir, log) {
|
||||
if (typ == null) {
|
||||
typ = access_value_type(instr[2])
|
||||
}
|
||||
// Narrow T_NUM to T_INT when both operands are T_INT
|
||||
if (typ == T_NUM && instr[3] != null && int_narrowable_ops[op] == true) {
|
||||
if (slot_is(slot_types, instr[2], T_INT)
|
||||
&& slot_is(slot_types, instr[3], T_INT)) {
|
||||
typ = T_INT
|
||||
}
|
||||
}
|
||||
slot_types[instr[rule[0]]] = typ
|
||||
}
|
||||
return null
|
||||
@@ -373,6 +387,34 @@ var streamline = function(ir, log) {
|
||||
max: T_NUM, min: T_NUM, remainder: T_NUM, modulo: T_NUM
|
||||
}
|
||||
|
||||
var narrow_arith_type = function(write_types, param_types, instr, typ) {
|
||||
var s2 = null
|
||||
var s3 = null
|
||||
var t2 = null
|
||||
var t3 = null
|
||||
if (typ != T_NUM || instr[3] == null || int_narrowable_ops[instr[0]] != true) {
|
||||
return typ
|
||||
}
|
||||
s2 = instr[2]
|
||||
s3 = instr[3]
|
||||
if (is_number(s2)) {
|
||||
t2 = write_types[s2]
|
||||
if (t2 == null && param_types != null && s2 < length(param_types)) {
|
||||
t2 = param_types[s2]
|
||||
}
|
||||
}
|
||||
if (is_number(s3)) {
|
||||
t3 = write_types[s3]
|
||||
if (t3 == null && param_types != null && s3 < length(param_types)) {
|
||||
t3 = param_types[s3]
|
||||
}
|
||||
}
|
||||
if (t2 == T_INT && t3 == T_INT) {
|
||||
return T_INT
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
var infer_slot_write_types = function(func, param_types) {
|
||||
var instructions = func.instructions
|
||||
var nr_args = func.nr_args != null ? func.nr_args : 0
|
||||
@@ -478,6 +520,7 @@ var streamline = function(ir, log) {
|
||||
if (typ == null) {
|
||||
typ = access_value_type(instr[2])
|
||||
}
|
||||
typ = narrow_arith_type(write_types, param_types, instr, typ)
|
||||
if (slot > 0 && slot > nr_args) {
|
||||
merge_backward(write_types, slot, typ)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user