// streamline.cm — mcode IR optimizer // Single forward pass: type inference + strength reduction var streamline = function(ir) { // Type constants var T_UNKNOWN = "unknown" var T_INT = "int" var T_FLOAT = "float" var T_NUM = "num" var T_TEXT = "text" var T_BOOL = "bool" var T_NULL = "null" // Integer arithmetic ops that produce integer results var int_result_ops = { add_int: true, sub_int: true, mul_int: true, div_int: true, mod_int: true } // Float arithmetic ops that produce float results var float_result_ops = { add_float: true, sub_float: true, mul_float: true, div_float: true, mod_float: true } // Comparison ops that produce bool results 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, not: true, and: true, or: true, is_int: true, is_text: true, is_num: true, is_bool: true, is_null: true, is_identical: true } // Type check opcodes and what type they verify var type_check_map = { is_int: T_INT, is_text: T_TEXT, is_num: T_NUM, is_bool: T_BOOL, is_null: T_NULL } // Determine the type of an access literal value var access_value_type = function(val) { if (is_number(val)) { if (is_integer(val)) { return T_INT } return T_FLOAT } if (is_text(val)) { return T_TEXT } return T_UNKNOWN } // Update slot_types for an instruction (shared tracking logic) var track_types = function(slot_types, instr) { var op = instr[0] var src_type = null if (op == "access") { slot_types[text(instr[1])] = access_value_type(instr[2]) } else if (op == "int") { slot_types[text(instr[1])] = T_INT } else if (op == "true" || op == "false") { slot_types[text(instr[1])] = T_BOOL } else if (op == "null") { slot_types[text(instr[1])] = T_NULL } else if (op == "move") { src_type = slot_types[text(instr[2])] if (src_type != null) { slot_types[text(instr[1])] = src_type } else { slot_types[text(instr[1])] = T_UNKNOWN } } else if (int_result_ops[op] == true) { slot_types[text(instr[1])] = T_INT } else if (float_result_ops[op] == true) { slot_types[text(instr[1])] = T_FLOAT } else if (op == "concat") { slot_types[text(instr[1])] = T_TEXT } else if (bool_result_ops[op] == true) { slot_types[text(instr[1])] = T_BOOL } else if (op == "load_field" || op == "load_index" || op == "load_dynamic") { slot_types[text(instr[1])] = T_UNKNOWN } else if (op == "invoke") { slot_types[text(instr[2])] = T_UNKNOWN } else if (op == "pop" || op == "get" || op == "function") { slot_types[text(instr[1])] = T_UNKNOWN } else if (op == "typeof") { slot_types[text(instr[1])] = T_TEXT } else if (op == "neg_int") { slot_types[text(instr[1])] = T_INT } else if (op == "neg_float") { slot_types[text(instr[1])] = T_FLOAT } else if (op == "bitnot" || op == "bitand" || op == "bitor" || op == "bitxor" || op == "shl" || op == "shr" || op == "ushr") { slot_types[text(instr[1])] = T_INT } return null } // Check if a slot has a known type (with T_NUM subsumption) var slot_is = function(slot_types, slot, typ) { var known = slot_types[text(slot)] if (known == null) { return false } if (known == typ) { return true } if (typ == T_NUM && (known == T_INT || known == T_FLOAT)) { return true } return false } // Optimize a single function's instructions var optimize_function = function(func) { var instructions = func.instructions var num_instr = 0 var slot_types = null var nop_counter = 0 var i = 0 var instr = null var op = null var dest = 0 var src = 0 var checked_type = null var next = null var next_op = null var target_label = null var src_known = null var jlen = 0 var j = 0 var peek = null if (instructions == null || length(instructions) == 0) { return null } num_instr = length(instructions) slot_types = {} // Peephole optimization pass: type tracking + strength reduction i = 0 while (i < num_instr) { instr = instructions[i] // Labels are join points: clear all type info (conservative) if (is_text(instr)) { slot_types = {} i = i + 1 continue } if (!is_array(instr)) { i = i + 1 continue } op = instr[0] // --- Peephole: type-check + jump where we know the type --- if (type_check_map[op] != null && i + 1 < num_instr) { dest = instr[1] src = instr[2] checked_type = type_check_map[op] next = instructions[i + 1] if (is_array(next)) { next_op = next[0] // Pattern: is_ t, x -> jump_false t, label if (next_op == "jump_false" && next[1] == dest) { target_label = next[2] if (slot_is(slot_types, src, checked_type)) { // Known match: check always true, never jumps — eliminate both nop_counter = nop_counter + 1 instructions[i] = "_nop_" + text(nop_counter) nop_counter = nop_counter + 1 instructions[i + 1] = "_nop_" + text(nop_counter) slot_types[text(dest)] = T_BOOL i = i + 2 continue } src_known = slot_types[text(src)] if (src_known != null && src_known != T_UNKNOWN && src_known != checked_type) { // Check for T_NUM subsumption: INT and FLOAT match T_NUM if (checked_type == T_NUM && (src_known == T_INT || src_known == T_FLOAT)) { // Actually matches — eliminate both nop_counter = nop_counter + 1 instructions[i] = "_nop_" + text(nop_counter) nop_counter = nop_counter + 1 instructions[i + 1] = "_nop_" + text(nop_counter) slot_types[text(dest)] = T_BOOL i = i + 2 continue } // Known mismatch: always jumps — nop the check, rewrite jump nop_counter = nop_counter + 1 instructions[i] = "_nop_" + text(nop_counter) jlen = length(next) instructions[i + 1] = ["jump", target_label, next[jlen - 2], next[jlen - 1]] slot_types[text(dest)] = T_UNKNOWN i = i + 2 continue } // Unknown: can't eliminate, but narrow type on fallthrough slot_types[text(dest)] = T_BOOL slot_types[text(src)] = checked_type i = i + 2 continue } // Pattern: is_ t, x -> jump_true t, label if (next_op == "jump_true" && next[1] == dest) { target_label = next[2] if (slot_is(slot_types, src, checked_type)) { // Known match: always true, always jumps — nop check, rewrite to jump nop_counter = nop_counter + 1 instructions[i] = "_nop_" + text(nop_counter) jlen = length(next) instructions[i + 1] = ["jump", target_label, next[jlen - 2], next[jlen - 1]] slot_types[text(dest)] = T_BOOL i = i + 2 continue } src_known = slot_types[text(src)] if (src_known != null && src_known != T_UNKNOWN && src_known != checked_type) { if (checked_type == T_NUM && (src_known == T_INT || src_known == T_FLOAT)) { // Actually matches T_NUM — always jumps nop_counter = nop_counter + 1 instructions[i] = "_nop_" + text(nop_counter) jlen = length(next) instructions[i + 1] = ["jump", target_label, next[jlen - 2], next[jlen - 1]] slot_types[text(dest)] = T_BOOL i = i + 2 continue } // Known mismatch: never jumps — eliminate both nop_counter = nop_counter + 1 instructions[i] = "_nop_" + text(nop_counter) nop_counter = nop_counter + 1 instructions[i + 1] = "_nop_" + text(nop_counter) slot_types[text(dest)] = T_BOOL i = i + 2 continue } // Unknown: can't optimize slot_types[text(dest)] = T_BOOL i = i + 2 continue } } // Standalone type check (no jump following): just track the result slot_types[text(dest)] = T_BOOL i = i + 1 continue } // --- Strength reduction: load_dynamic / store_dynamic --- if (op == "load_dynamic") { if (slot_is(slot_types, instr[3], T_TEXT)) { instr[0] = "load_field" } else if (slot_is(slot_types, instr[3], T_INT)) { instr[0] = "load_index" } slot_types[text(instr[1])] = T_UNKNOWN i = i + 1 continue } if (op == "store_dynamic") { if (slot_is(slot_types, instr[3], T_TEXT)) { instr[0] = "store_field" } else if (slot_is(slot_types, instr[3], T_INT)) { instr[0] = "store_index" } i = i + 1 continue } // --- Standard type tracking --- track_types(slot_types, instr) i = i + 1 } // Second pass: remove dead jumps (jump to the immediately next label) i = 0 while (i < num_instr) { instr = instructions[i] if (is_array(instr) && instr[0] == "jump") { target_label = instr[1] // Check if the very next non-nop item is that label j = i + 1 while (j < num_instr) { peek = instructions[j] if (is_text(peek)) { if (peek == target_label) { nop_counter = nop_counter + 1 instructions[i] = "_nop_" + text(nop_counter) } break } if (is_array(peek)) { break } j = j + 1 } } i = i + 1 } return null } // Process main function if (ir.main != null) { optimize_function(ir.main) } // Process all sub-functions var fi = 0 if (ir.functions != null) { fi = 0 while (fi < length(ir.functions)) { optimize_function(ir.functions[fi]) fi = fi + 1 } } return ir } return streamline