merge add

This commit is contained in:
2026-02-13 08:09:12 -06:00
parent f7e2ff13b5
commit 0acaabd5fa
14 changed files with 98386 additions and 107814 deletions

View File

@@ -99,7 +99,7 @@ var track_types = function(slot_types, instr) {
slot_types[text(instr[1])] = T_RECORD slot_types[text(instr[1])] = T_RECORD
} else if (op == "function") { } else if (op == "function") {
slot_types[text(instr[1])] = T_FUNCTION slot_types[text(instr[1])] = T_FUNCTION
} else if (op == "invoke") { } else if (op == "invoke" || op == "tail_invoke") {
slot_types[text(instr[2])] = T_UNKNOWN slot_types[text(instr[2])] = T_UNKNOWN
} else if (op == "load_field" || op == "load_index" || op == "load_dynamic") { } else if (op == "load_field" || op == "load_index" || op == "load_dynamic") {
slot_types[text(instr[1])] = T_UNKNOWN slot_types[text(instr[1])] = T_UNKNOWN
@@ -107,6 +107,9 @@ var track_types = function(slot_types, instr) {
slot_types[text(instr[1])] = T_UNKNOWN slot_types[text(instr[1])] = T_UNKNOWN
} else if (op == "length") { } else if (op == "length") {
slot_types[text(instr[1])] = T_INT slot_types[text(instr[1])] = T_INT
} else if (op == "add" || op == "subtract" || op == "multiply" ||
op == "divide" || op == "modulo" || op == "pow" || op == "negate") {
slot_types[text(instr[1])] = T_UNKNOWN
} }
return null return null
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

197
mcode.cm
View File

@@ -273,157 +273,19 @@ var mcode = function(ast) {
return node.kind == "null" return node.kind == "null"
} }
// emit_add_decomposed: int path -> text path -> float path -> disrupt // emit_add_decomposed: emit generic add (VM dispatches int/float/text)
// reads _bp_dest, _bp_left, _bp_right, _bp_ln, _bp_rn from closure // reads _bp_dest, _bp_left, _bp_right, _bp_ln, _bp_rn from closure
var emit_add_decomposed = function() { var emit_add_decomposed = function() {
var dest = _bp_dest // Known text+text → concat directly (skip numeric check in VM)
var left = _bp_left if (is_known_text(_bp_ln) && is_known_text(_bp_rn)) {
var right = _bp_right emit_3("concat", _bp_dest, _bp_left, _bp_right)
var t0 = 0
var t1 = 0
var left_is_int = is_known_int(_bp_ln)
var left_is_text = is_known_text(_bp_ln)
var left_is_num = is_known_number(_bp_ln)
var right_is_int = is_known_int(_bp_rn)
var right_is_text = is_known_text(_bp_rn)
var right_is_num = is_known_number(_bp_rn)
var not_int = null
var not_text = null
var done = null
var err = null
// Both sides known int
if (left_is_int && right_is_int) {
emit_3("add_int", dest, left, right)
return null return null
} }
// Both sides known text emit_3("add", _bp_dest, _bp_left, _bp_right)
if (left_is_text && right_is_text) {
emit_3("concat", dest, left, right)
return null
}
// Both sides known number (but not both int)
if (left_is_num && right_is_num) {
if (left_is_int && right_is_int) {
emit_3("add_int", dest, left, right)
} else {
emit_3("add_float", dest, left, right)
}
return null
}
not_int = gen_label("add_ni")
not_text = gen_label("add_nt")
done = gen_label("add_done")
err = gen_label("add_err")
// Int path
t0 = alloc_slot()
if (!left_is_int) {
emit_2("is_int", t0, left)
emit_jump_cond("jump_false", t0, not_int)
}
t1 = alloc_slot()
if (!right_is_int) {
emit_2("is_int", t1, right)
emit_jump_cond("jump_false", t1, not_int)
}
emit_3("add_int", dest, left, right)
emit_jump(done)
// Text path
emit_label(not_int)
if (!left_is_text) {
emit_2("is_text", t0, left)
emit_jump_cond("jump_false", t0, not_text)
}
if (!right_is_text) {
emit_2("is_text", t1, right)
emit_jump_cond("jump_false", t1, not_text)
}
emit_3("concat", dest, left, right)
emit_jump(done)
// Float path
emit_label(not_text)
if (!left_is_num) {
emit_2("is_num", t0, left)
emit_jump_cond("jump_false", t0, err)
}
if (!right_is_num) {
emit_2("is_num", t1, right)
emit_jump_cond("jump_false", t1, err)
}
emit_3("add_float", dest, left, right)
emit_jump(done)
emit_label(err)
emit_0("disrupt")
emit_label(done)
return null return null
} }
// emit_numeric_binop: int path -> float path -> disrupt // emit_numeric_binop removed — generic ops emitted directly via passthrough
// reads _bp_dest, _bp_left, _bp_right, _bp_ln, _bp_rn from closure
var emit_numeric_binop = function(int_op, float_op) {
var dest = _bp_dest
var left = _bp_left
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 right_is_int = is_known_int(_bp_rn)
var right_is_num = is_known_number(_bp_rn)
var not_int = null
var done = null
var err = null
// Both sides known int
if (left_is_int && right_is_int) {
emit_3(int_op, dest, left, right)
return null
}
// Both sides known number (but not both int)
if (left_is_num && right_is_num) {
emit_3(float_op, dest, left, right)
return null
}
not_int = gen_label("num_ni")
done = gen_label("num_done")
err = gen_label("num_err")
t0 = alloc_slot()
if (!left_is_int) {
emit_2("is_int", t0, left)
emit_jump_cond("jump_false", t0, not_int)
}
t1 = alloc_slot()
if (!right_is_int) {
emit_2("is_int", t1, right)
emit_jump_cond("jump_false", t1, not_int)
}
emit_3(int_op, dest, left, right)
emit_jump(done)
emit_label(not_int)
if (!left_is_num) {
emit_2("is_num", t0, left)
emit_jump_cond("jump_false", t0, err)
}
if (!right_is_num) {
emit_2("is_num", t1, right)
emit_jump_cond("jump_false", t1, err)
}
emit_3(float_op, dest, left, right)
emit_jump(done)
emit_label(err)
emit_0("disrupt")
emit_label(done)
return null
}
// emit_eq_decomposed: identical -> int -> float -> text -> null -> bool -> mismatch(false) // emit_eq_decomposed: identical -> int -> float -> text -> null -> bool -> mismatch(false)
// reads _bp_dest, _bp_left, _bp_right from closure // reads _bp_dest, _bp_left, _bp_right from closure
@@ -649,41 +511,9 @@ var mcode = function(ast) {
return null return null
} }
// emit_neg_decomposed: int path -> float path -> disrupt // emit_neg_decomposed: emit generic negate (VM dispatches int/float)
var emit_neg_decomposed = function(dest, src, src_node) { var emit_neg_decomposed = function(dest, src, src_node) {
var t0 = 0 emit_2("negate", dest, src)
var not_int = null
var done = null
var err = null
if (is_known_int(src_node)) {
emit_2("neg_int", dest, src)
return null
}
if (is_known_number(src_node)) {
emit_2("neg_float", dest, src)
return null
}
not_int = gen_label("neg_ni")
done = gen_label("neg_done")
err = gen_label("neg_err")
t0 = alloc_slot()
emit_2("is_int", t0, src)
emit_jump_cond("jump_false", t0, not_int)
emit_2("neg_int", dest, src)
emit_jump(done)
emit_label(not_int)
emit_2("is_num", t0, src)
emit_jump_cond("jump_false", t0, err)
emit_2("neg_float", dest, src)
emit_jump(done)
emit_label(err)
emit_0("disrupt")
emit_label(done)
return null return null
} }
@@ -695,14 +525,6 @@ var mcode = function(ast) {
_bp_right = right _bp_right = right
if (op_str == "add") { if (op_str == "add") {
emit_add_decomposed() emit_add_decomposed()
} else if (op_str == "subtract") {
emit_numeric_binop("sub_int", "sub_float")
} else if (op_str == "multiply") {
emit_numeric_binop("mul_int", "mul_float")
} else if (op_str == "divide") {
emit_numeric_binop("div_int", "div_float")
} else if (op_str == "modulo") {
emit_numeric_binop("mod_int", "mod_float")
} else if (op_str == "eq") { } else if (op_str == "eq") {
emit_eq_decomposed() emit_eq_decomposed()
} else if (op_str == "ne") { } else if (op_str == "ne") {
@@ -716,7 +538,8 @@ var mcode = function(ast) {
} else if (op_str == "ge") { } else if (op_str == "ge") {
emit_relational("ge_int", "ge_float", "ge_text") emit_relational("ge_int", "ge_float", "ge_text")
} else { } else {
// Passthrough for bitwise, pow, in, etc. // Passthrough for subtract, multiply, divide, modulo,
// bitwise, pow, in, etc.
emit_3(op_str, dest, left, right) emit_3(op_str, dest, left, right)
} }
return null return null

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -277,6 +277,51 @@ var qbe_emit = function(ir, qbe) {
continue continue
} }
// --- Generic arithmetic (VM dispatches int/float) ---
if (op == "add") {
p = fresh()
emit(qbe.add(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "subtract") {
p = fresh()
emit(qbe.sub(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "multiply") {
p = fresh()
emit(qbe.mul(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "divide") {
p = fresh()
emit(qbe.div(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "modulo") {
p = fresh()
emit(qbe.mod(p, "%ctx", s(a2), s(a3)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
if (op == "negate") {
p = fresh()
emit(qbe.neg(p, "%ctx", s(a2)))
emit(` ${s(a1)} =l copy %${p}`)
wb(a1)
continue
}
// --- String concat --- // --- String concat ---
if (op == "concat") { if (op == "concat") {

File diff suppressed because it is too large Load Diff

View File

@@ -2392,7 +2392,13 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
/* Text */ /* Text */
else if (strcmp(op, "concat") == 0) { ABC3(MACH_CONCAT); } else if (strcmp(op, "concat") == 0) { ABC3(MACH_CONCAT); }
/* Generic arithmetic */ /* Generic arithmetic */
else if (strcmp(op, "add") == 0) { ABC3(MACH_ADD); }
else if (strcmp(op, "subtract") == 0) { ABC3(MACH_SUB); }
else if (strcmp(op, "multiply") == 0) { ABC3(MACH_MUL); }
else if (strcmp(op, "divide") == 0) { ABC3(MACH_DIV); }
else if (strcmp(op, "modulo") == 0) { ABC3(MACH_MOD); }
else if (strcmp(op, "pow") == 0) { ABC3(MACH_POW); } else if (strcmp(op, "pow") == 0) { ABC3(MACH_POW); }
else if (strcmp(op, "negate") == 0) { AB2(MACH_NEG); }
/* Typed integer comparisons */ /* Typed integer comparisons */
else if (strcmp(op, "eq_int") == 0) { ABC3(MACH_EQ_INT); } 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, "ne_int") == 0) { ABC3(MACH_NE_INT); }

View File

@@ -43,6 +43,10 @@ var streamline = function(ir, log) {
add_float: true, sub_float: true, mul_float: true, add_float: true, sub_float: true, mul_float: true,
div_float: true, mod_float: true div_float: true, mod_float: true
} }
var numeric_ops = {
add: true, subtract: true, multiply: true,
divide: true, modulo: true, pow: true
}
var bool_result_ops = { var bool_result_ops = {
eq_int: true, ne_int: true, lt_int: true, gt_int: true, eq_int: true, ne_int: true, lt_int: true, gt_int: true,
le_int: true, ge_int: true, le_int: true, ge_int: true,
@@ -159,10 +163,12 @@ var streamline = function(ir, log) {
slot_types[text(instr[1])] = T_FUNCTION slot_types[text(instr[1])] = T_FUNCTION
} else if (op == "length") { } else if (op == "length") {
slot_types[text(instr[1])] = T_INT slot_types[text(instr[1])] = T_INT
} else if (op == "neg_int") { } else if (op == "negate" || op == "neg_int") {
slot_types[text(instr[1])] = T_INT slot_types[text(instr[1])] = T_UNKNOWN
} else if (op == "neg_float") { } else if (op == "neg_float") {
slot_types[text(instr[1])] = T_FLOAT slot_types[text(instr[1])] = T_FLOAT
} else if (numeric_ops[op] == true) {
slot_types[text(instr[1])] = T_UNKNOWN
} else if (op == "bitnot" || op == "bitand" || op == "bitor" || } else if (op == "bitnot" || op == "bitand" || op == "bitor" ||
op == "bitxor" || op == "shl" || op == "shr" || op == "ushr") { op == "bitxor" || op == "shl" || op == "shr" || op == "ushr") {
slot_types[text(instr[1])] = T_INT slot_types[text(instr[1])] = T_INT
@@ -266,6 +272,12 @@ var streamline = function(ir, log) {
merge_backward(backward_types, instr[3], T_INT) merge_backward(backward_types, instr[3], T_INT)
} else if (op == "neg_int" || op == "bitnot") { } else if (op == "neg_int" || op == "bitnot") {
merge_backward(backward_types, instr[2], T_INT) merge_backward(backward_types, instr[2], T_INT)
} else if (op == "subtract" || op == "multiply" ||
op == "divide" || op == "modulo" || op == "pow") {
merge_backward(backward_types, instr[2], T_NUM)
merge_backward(backward_types, instr[3], T_NUM)
} else if (op == "negate") {
merge_backward(backward_types, instr[2], T_NUM)
} else if (op == "add_float" || op == "sub_float" || op == "mul_float" || } else if (op == "add_float" || op == "sub_float" || op == "mul_float" ||
op == "div_float" || op == "mod_float" || op == "div_float" || op == "mod_float" ||
op == "eq_float" || op == "ne_float" || op == "lt_float" || op == "eq_float" || op == "ne_float" || op == "lt_float" ||
@@ -395,6 +407,9 @@ var streamline = function(ir, log) {
} else if (op == "neg_float") { } else if (op == "neg_float") {
slot = instr[1] slot = instr[1]
typ = T_FLOAT typ = T_FLOAT
} else if (op == "negate") {
slot = instr[1]
typ = T_UNKNOWN
} else if (op == "concat") { } else if (op == "concat") {
slot = instr[1] slot = instr[1]
typ = T_TEXT typ = T_TEXT

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,7 @@ var slot_positions = {
// Unary — dest, src // Unary — dest, src
move: [0, 1], move: [0, 1],
not: [0, 1], not: [0, 1],
negate: [0, 1],
neg_int: [0, 1], neg_int: [0, 1],
neg_float: [0, 1], neg_float: [0, 1],
bitnot: [0, 1], bitnot: [0, 1],
@@ -123,7 +124,7 @@ var slot_positions = {
var writes_dest = { var writes_dest = {
access: true, int: true, true: true, false: true, null: true, access: true, int: true, true: true, false: true, null: true,
function: true, array: true, record: true, function: true, array: true, record: true,
move: true, not: true, neg_int: true, neg_float: true, bitnot: true, move: true, not: true, negate: true, neg_int: true, neg_float: true, bitnot: true,
length: true, typeof: true, length: true, typeof: true,
is_int: true, is_text: true, is_num: true, is_int: true, is_text: true, is_num: true,
is_bool: true, is_null: true, is_array: true, is_bool: true, is_null: true, is_array: true,