// dump_stream.cm — show mcode IR before and after streamlining // // Usage: ./cell --core . dump_stream.cm var fd = use("fd") var json = use("json") var tokenize = use("tokenize") var parse = use("parse") var fold = use("fold") var mcode = use("mcode") var streamline = use("streamline") if (length(args) < 1) { print("usage: cell --core . dump_stream.cm ") return } var filename = args[0] var src = text(fd.slurp(filename)) var tok = tokenize(src, filename) var ast = parse(tok.tokens, src, filename, tokenize) var folded = fold(ast) var compiled = mcode(folded) // Deep copy IR for before snapshot var before = json.decode(json.encode(compiled)) var optimized = streamline(compiled) var pad_right = function(s, w) { var r = s while (length(r) < w) { r = r + " " } return r } var fmt_val = function(v) { if (is_null(v)) { return "null" } if (is_number(v)) { return text(v) } if (is_text(v)) { return `"${v}"` } if (is_object(v)) { return json.encode(v) } if (is_logical(v)) { return v ? "true" : "false" } return text(v) } var count_stats = function(func) { var instrs = func.instructions var total = 0 var nops = 0 var calls = 0 var i = 0 var instr = null if (instrs == null) { return {total: 0, nops: 0, real: 0, calls: 0} } while (i < length(instrs)) { instr = instrs[i] if (is_text(instr)) { if (starts_with(instr, "_nop_")) { nops = nops + 1 } } else if (is_array(instr)) { total = total + 1 if (instr[0] == "invoke") { calls = calls + 1 } } i = i + 1 } return {total: total, nops: nops, real: total - nops, calls: calls} } var dump_function = function(func, show_nops) { var instrs = func.instructions var i = 0 var pc = 0 var instr = null var op = null var n = 0 var parts = null var j = 0 var operands = null var pc_str = null var op_str = null if (instrs == null || length(instrs) == 0) { return null } while (i < length(instrs)) { instr = instrs[i] if (is_text(instr)) { if (starts_with(instr, "_nop_")) { if (show_nops) { print(` ${pad_right(text(pc), 5)} --- nop ---`) pc = pc + 1 } } else { print(`${instr}:`) } } else if (is_array(instr)) { op = instr[0] n = length(instr) parts = [] j = 1 while (j < n - 2) { push(parts, fmt_val(instr[j])) j = j + 1 } operands = text(parts, ", ") pc_str = pad_right(text(pc), 5) op_str = pad_right(op, 14) print(` ${pc_str} ${op_str} ${operands}`) pc = pc + 1 } i = i + 1 } return null } var dump_pair = function(before_func, after_func, name) { var nr_args = after_func.nr_args != null ? after_func.nr_args : 0 var nr_slots = after_func.nr_slots != null ? after_func.nr_slots : 0 var b_stats = count_stats(before_func) var a_stats = count_stats(after_func) var eliminated = a_stats.nops print(`\n=== ${name} (args=${text(nr_args)}, slots=${text(nr_slots)}) ===`) print(` before: ${text(b_stats.total)} instructions, ${text(b_stats.calls)} invokes`) print(` after: ${text(a_stats.real)} instructions (${text(eliminated)} eliminated), ${text(a_stats.calls)} invokes`) print("\n -- streamlined --") dump_function(after_func, false) return null } var main_name = null var fi = 0 var func = null var bfunc = null var fname = null // Dump main if (optimized.main != null && before.main != null) { main_name = optimized.name != null ? optimized.name : "
" dump_pair(before.main, optimized.main, main_name) } // Dump sub-functions if (optimized.functions != null && before.functions != null) { fi = 0 while (fi < length(optimized.functions)) { func = optimized.functions[fi] bfunc = before.functions[fi] fname = func.name != null ? func.name : `` dump_pair(bfunc, func, `[${text(fi)}] ${fname}`) fi = fi + 1 } }