172 lines
4.3 KiB
Plaintext
172 lines
4.3 KiB
Plaintext
// streamline.ce — run the full compile + optimize pipeline
|
|
//
|
|
// Usage:
|
|
// pit streamline <file> Full optimized IR as JSON (default)
|
|
// pit streamline --stats <file> Summary stats per function
|
|
// pit streamline --ir <file> Human-readable IR
|
|
// pit streamline --check <file> Warnings only (e.g. high slot count)
|
|
|
|
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")
|
|
|
|
var show_stats = false
|
|
var show_ir = false
|
|
var show_check = false
|
|
var filename = null
|
|
var i = 0
|
|
|
|
for (i = 0; i < length(args); i++) {
|
|
if (args[i] == '--stats') {
|
|
show_stats = true
|
|
} else if (args[i] == '--ir') {
|
|
show_ir = true
|
|
} else if (args[i] == '--check') {
|
|
show_check = true
|
|
} else if (!starts_with(args[i], '-')) {
|
|
filename = args[i]
|
|
}
|
|
}
|
|
|
|
if (!filename) {
|
|
print("usage: pit streamline [--stats] [--ir] [--check] <file>")
|
|
$stop()
|
|
}
|
|
|
|
var src = text(fd.slurp(filename))
|
|
var result = tokenize(src, filename)
|
|
var ast = parse(result.tokens, src, filename, tokenize)
|
|
var folded = fold(ast)
|
|
var compiled = mcode(folded)
|
|
|
|
// Deep copy for before snapshot (needed by --stats)
|
|
var before = null
|
|
if (show_stats) {
|
|
before = json.decode(json.encode(compiled))
|
|
}
|
|
|
|
var optimized = streamline(compiled)
|
|
|
|
// If no flags, default to full JSON output
|
|
if (!show_stats && !show_ir && !show_check) {
|
|
print(json.encode(optimized, true))
|
|
$stop()
|
|
}
|
|
|
|
// --- Helpers ---
|
|
|
|
var ir_stats = use("ir_stats")
|
|
|
|
var pad_right = function(s, w) {
|
|
var r = s
|
|
while (length(r) < w) {
|
|
r = r + " "
|
|
}
|
|
return r
|
|
}
|
|
|
|
var count_nops = function(func) {
|
|
var instrs = func.instructions
|
|
var nops = 0
|
|
var i = 0
|
|
if (instrs == null) return 0
|
|
while (i < length(instrs)) {
|
|
if (is_text(instrs[i]) && starts_with(instrs[i], "_nop_")) {
|
|
nops = nops + 1
|
|
}
|
|
i = i + 1
|
|
}
|
|
return nops
|
|
}
|
|
|
|
var print_func_stats = function(func, before_func, name) {
|
|
var nr_args = func.nr_args != null ? func.nr_args : 0
|
|
var nr_slots = func.nr_slots != null ? func.nr_slots : 0
|
|
var nr_close = func.nr_close_slots != null ? func.nr_close_slots : 0
|
|
var stats = ir_stats.detailed_stats(func)
|
|
var nops = count_nops(func)
|
|
var before_stats = before_func ? ir_stats.detailed_stats(before_func) : null
|
|
var before_total = before_stats ? before_stats.instr : stats.instr
|
|
|
|
print(` ${name}`)
|
|
print(` args=${text(nr_args)} slots=${text(nr_slots)} close_slots=${text(nr_close)}`)
|
|
print(` instructions: ${text(stats.instr)} total, ${text(nops)} nops eliminated`)
|
|
if (before_stats) {
|
|
print(` before: ${text(before_total)} after: ${text(stats.instr - nops)}`)
|
|
}
|
|
print(` load=${text(stats.load)} store=${text(stats.store)} branch=${text(stats.branch)} call=${text(stats.call)}`)
|
|
print(` guard=${text(stats.guard)} arith=${text(stats.arith)} move=${text(stats.move)} const=${text(stats.const)}`)
|
|
|
|
if (nr_slots > 200) {
|
|
print(` WARNING: nr_slots=${text(nr_slots)} approaching 255 limit`)
|
|
}
|
|
}
|
|
|
|
var print_func_ir = function(func, name) {
|
|
var ir_text = ir_stats.canonical_ir(func, name, {show_nops: true})
|
|
print(ir_text)
|
|
}
|
|
|
|
var check_func = function(func, name) {
|
|
var nr_slots = func.nr_slots != null ? func.nr_slots : 0
|
|
if (nr_slots > 200) {
|
|
print(`WARNING: ${name} has ${text(nr_slots)} slots (approaching 255 limit)`)
|
|
}
|
|
}
|
|
|
|
// --- Process functions ---
|
|
|
|
var main_name = optimized.name != null ? optimized.name : "<main>"
|
|
var fi = 0
|
|
var func = null
|
|
var bfunc = null
|
|
var fname = null
|
|
|
|
if (show_stats) {
|
|
print(`\n--- Stats for ${filename} ---`)
|
|
}
|
|
|
|
// Main function
|
|
if (optimized.main != null) {
|
|
if (show_stats) {
|
|
print_func_stats(optimized.main, before ? before.main : null, main_name)
|
|
}
|
|
if (show_ir) {
|
|
print_func_ir(optimized.main, main_name)
|
|
}
|
|
if (show_check) {
|
|
check_func(optimized.main, main_name)
|
|
}
|
|
}
|
|
|
|
// Sub-functions
|
|
if (optimized.functions != null) {
|
|
fi = 0
|
|
while (fi < length(optimized.functions)) {
|
|
func = optimized.functions[fi]
|
|
bfunc = before ? before.functions[fi] : null
|
|
fname = func.name != null ? func.name : `<func_${text(fi)}>`
|
|
|
|
if (show_stats) {
|
|
print_func_stats(func, bfunc, fname)
|
|
}
|
|
if (show_ir) {
|
|
print_func_ir(func, fname)
|
|
}
|
|
if (show_check) {
|
|
check_func(func, fname)
|
|
}
|
|
fi = fi + 1
|
|
}
|
|
}
|
|
|
|
if (show_stats) {
|
|
print('---')
|
|
}
|
|
|
|
$stop()
|