167 lines
3.9 KiB
Plaintext
167 lines
3.9 KiB
Plaintext
// dump_stream.cm — show mcode IR before and after streamlining
|
|
//
|
|
// Usage: ./cell --core . dump_stream.cm <file.ce|file.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 <file>")
|
|
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 : "<main>"
|
|
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 : `<func_${text(fi)}>`
|
|
dump_pair(bfunc, func, `[${text(fi)}] ${fname}`)
|
|
fi = fi + 1
|
|
}
|
|
}
|