201 lines
4.6 KiB
Plaintext
201 lines
4.6 KiB
Plaintext
// ir_report.ce — optimizer flight recorder CLI
|
|
//
|
|
// Usage: ./cell --core . ir_report.ce [options] <file.cm|file.ce>
|
|
//
|
|
// Options:
|
|
// --summary Per-pass JSON summaries (default)
|
|
// --events Include rewrite events
|
|
// --types Include type deltas
|
|
// --ir-before=PASS Print canonical IR before PASS
|
|
// --ir-after=PASS Print canonical IR after PASS
|
|
// --ir-all Print canonical IR before/after every pass
|
|
// --full Everything (summary + events + types + ir-all)
|
|
|
|
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 ir_stats = use("ir_stats")
|
|
|
|
// --- Parse arguments ---
|
|
|
|
var filename = null
|
|
var opt_events = false
|
|
var opt_types = false
|
|
var opt_ir_before = null
|
|
var opt_ir_after = null
|
|
var opt_ir_all = false
|
|
var i = 0
|
|
var arg = null
|
|
var p = null
|
|
var e = null
|
|
var td = null
|
|
|
|
while (i < length(args)) {
|
|
arg = args[i]
|
|
if (arg == "--events") {
|
|
opt_events = true
|
|
} else if (arg == "--types") {
|
|
opt_types = true
|
|
} else if (arg == "--ir-all") {
|
|
opt_ir_all = true
|
|
} else if (arg == "--full") {
|
|
opt_events = true
|
|
opt_types = true
|
|
opt_ir_all = true
|
|
} else if (arg == "--summary") {
|
|
// default, no-op
|
|
} else if (starts_with(arg, "--ir-before=")) {
|
|
opt_ir_before = text(arg, 12)
|
|
} else if (starts_with(arg, "--ir-after=")) {
|
|
opt_ir_after = text(arg, 11)
|
|
} else if (!starts_with(arg, "--")) {
|
|
filename = arg
|
|
} else {
|
|
print(`unknown option: ${arg}\n`)
|
|
print("usage: cell --core . ir_report.ce [options] <file>\n")
|
|
$stop()
|
|
}
|
|
i = i + 1
|
|
}
|
|
|
|
if (filename == null) {
|
|
print("usage: cell --core . ir_report.ce [options] <file.cm|file.ce>\n")
|
|
print(" --summary per-pass JSON summaries (default)\n")
|
|
print(" --events include rewrite events\n")
|
|
print(" --types include type deltas\n")
|
|
print(" --ir-before=PASS print canonical IR before PASS\n")
|
|
print(" --ir-after=PASS print canonical IR after PASS\n")
|
|
print(" --ir-all print canonical IR before/after every pass\n")
|
|
print(" --full everything\n")
|
|
$stop()
|
|
}
|
|
|
|
// --- Compile ---
|
|
|
|
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)
|
|
|
|
// --- Determine which passes need IR snapshots ---
|
|
|
|
var need_snapshots = opt_ir_all || opt_ir_before != null || opt_ir_after != null
|
|
|
|
// Deep copy for before snapshot if we need IR printing
|
|
var before_ir = null
|
|
if (need_snapshots) {
|
|
before_ir = json.decode(json.encode(compiled))
|
|
}
|
|
|
|
// --- Set up log ---
|
|
|
|
var log = {
|
|
passes: [],
|
|
events: null,
|
|
type_deltas: null
|
|
}
|
|
|
|
if (opt_events) {
|
|
log.events = []
|
|
}
|
|
if (opt_types) {
|
|
log.type_deltas = []
|
|
}
|
|
|
|
// --- Run optimizer ---
|
|
|
|
var optimized = streamline(compiled, log)
|
|
|
|
// --- Output ---
|
|
|
|
var emit = function(obj) {
|
|
print(json.encode(obj))
|
|
print("\n")
|
|
}
|
|
|
|
// Pass summaries (always)
|
|
i = 0
|
|
while (i < length(log.passes)) {
|
|
p = log.passes[i]
|
|
p.type = "pass"
|
|
emit(p)
|
|
i = i + 1
|
|
}
|
|
|
|
// Rewrite events
|
|
if (opt_events && log.events != null) {
|
|
i = 0
|
|
while (i < length(log.events)) {
|
|
e = log.events[i]
|
|
e.type = "event"
|
|
emit(e)
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
// Type deltas
|
|
if (opt_types && log.type_deltas != null) {
|
|
i = 0
|
|
while (i < length(log.type_deltas)) {
|
|
td = log.type_deltas[i]
|
|
td.type = "types"
|
|
emit(td)
|
|
i = i + 1
|
|
}
|
|
}
|
|
|
|
// --- Canonical IR printing ---
|
|
|
|
var print_ir = function(ir_obj, when_label, pass_name) {
|
|
var fname = null
|
|
var fi = 0
|
|
var func = null
|
|
if (ir_obj.main != null) {
|
|
fname = ir_obj.name != null ? ir_obj.name : "<main>"
|
|
emit({
|
|
type: "ir",
|
|
when: when_label,
|
|
pass: pass_name,
|
|
fn: fname,
|
|
text: ir_stats.canonical_ir(ir_obj.main, fname, {show_nops: true})
|
|
})
|
|
}
|
|
if (ir_obj.functions != null) {
|
|
fi = 0
|
|
while (fi < length(ir_obj.functions)) {
|
|
func = ir_obj.functions[fi]
|
|
fname = func.name != null ? func.name : `<func_${text(fi)}>`
|
|
emit({
|
|
type: "ir",
|
|
when: when_label,
|
|
pass: pass_name,
|
|
fn: fname,
|
|
text: ir_stats.canonical_ir(func, fname, {show_nops: true})
|
|
})
|
|
fi = fi + 1
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
if (need_snapshots) {
|
|
if (opt_ir_all) {
|
|
print_ir(before_ir, "before", "all")
|
|
print_ir(optimized, "after", "all")
|
|
} else {
|
|
if (opt_ir_before != null) {
|
|
print_ir(before_ir, "before", opt_ir_before)
|
|
}
|
|
if (opt_ir_after != null) {
|
|
print_ir(optimized, "after", opt_ir_after)
|
|
}
|
|
}
|
|
}
|
|
|
|
$stop()
|