diff --git a/build.ce b/build.ce index 0bc20318..7d3b445a 100644 --- a/build.ce +++ b/build.ce @@ -6,6 +6,7 @@ // cell build Build dynamic library for specific package // cell build -t Cross-compile dynamic libraries for target platform // cell build -b Build type: release (default), debug, or minsize +// cell build --verbose Print resolved flags, commands, and cache status var build = use('build') var shop = use('internal/shop') @@ -15,6 +16,7 @@ var fd = use('fd') var target = null var target_package = null var buildtype = 'release' +var verbose = false var force_rebuild = false var dry_run = false var i = 0 @@ -55,6 +57,8 @@ for (i = 0; i < length(args); i++) { } } else if (args[i] == '--force') { force_rebuild = true + } else if (args[i] == '--verbose' || args[i] == '-v') { + verbose = true } else if (args[i] == '--dry-run') { dry_run = true } else if (args[i] == '--list-targets') { @@ -104,7 +108,7 @@ if (target_package) { // Build single package log.console('Building ' + target_package + '...') _build = function() { - lib = build.build_dynamic(target_package, target, buildtype) + lib = build.build_dynamic(target_package, target, buildtype, {verbose: verbose}) if (lib) { log.console(`Built ${text(length(lib))} module(s)`) } @@ -116,7 +120,7 @@ if (target_package) { } else { // Build all packages log.console('Building all packages...') - results = build.build_all_dynamic(target, buildtype) + results = build.build_all_dynamic(target, buildtype, {verbose: verbose}) success = 0 failed = 0 diff --git a/build.cm b/build.cm index 1b393c19..41ae6af0 100644 --- a/build.cm +++ b/build.cm @@ -172,6 +172,11 @@ Build.compile_file = function(pkg, file, target, opts) { var cmd_str = text(cmd_parts, ' ') + if (_opts.verbose) { + print('[verbose] CFLAGS: ' + text(cflags, ' ')) + print('[verbose] compile: ' + cmd_str) + } + // Content hash: command + file content var file_content = fd.slurp(src_path) var hash_input = cmd_str + '\n' + text(file_content) @@ -183,8 +188,10 @@ Build.compile_file = function(pkg, file, target, opts) { // Check if already compiled if (fd.is_file(obj_path)) { + if (_opts.verbose) print('[verbose] cache hit: ' + file) return obj_path } + if (_opts.verbose) print('[verbose] cache miss: ' + file) // Compile — capture stderr to detect missing-header vs real errors var err_path = '/tmp/cell_build_err_' + hash + '.log' @@ -308,6 +315,10 @@ Build.build_module_dylib = function(pkg, file, target, opts) { var cmd_str = null var ret = null + if (_opts.verbose) { + print('[verbose] LDFLAGS: ' + text(resolved_ldflags, ' ')) + } + if (!fd.is_file(dylib_path)) { cmd_parts = [cc, '-shared', '-fPIC'] @@ -340,6 +351,7 @@ Build.build_module_dylib = function(pkg, file, target, opts) { push(cmd_parts, '"' + dylib_path + '"') cmd_str = text(cmd_parts, ' ') + if (_opts.verbose) print('[verbose] link: ' + cmd_str) log.console('Linking module ' + file + ' -> ' + fd.basename(dylib_path)) ret = os.system(cmd_str) if (ret != 0) { @@ -361,6 +373,7 @@ Build.build_module_dylib = function(pkg, file, target, opts) { ensure_dir(install_dir) var install_path = shop.get_lib_dir() + '/' + shop.lib_name_for_package(pkg) + '/' + file_stem + dylib_ext fd.slurpwrite(install_path, fd.slurp(dylib_path)) + if (_opts.verbose) print('[verbose] install: ' + install_path) return dylib_path } @@ -368,9 +381,10 @@ Build.build_module_dylib = function(pkg, file, target, opts) { // Build a dynamic library for a package (one dylib per C file) // Returns array of {file, symbol, dylib} for each module // Also writes a manifest mapping symbols to dylib paths -Build.build_dynamic = function(pkg, target, buildtype) { +Build.build_dynamic = function(pkg, target, buildtype, opts) { var _target = target || Build.detect_host_target() var _buildtype = buildtype || 'release' + var _opts = opts || {} var c_files = pkg_tools.get_c_files(pkg, _target, true) var results = [] @@ -382,13 +396,13 @@ Build.build_dynamic = function(pkg, target, buildtype) { var sources = pkg_tools.get_sources(pkg) var support_objects = [] arrfor(sources, function(src_file) { - var obj = Build.compile_file(pkg, src_file, _target, {buildtype: _buildtype, cflags: cached_cflags}) + var obj = Build.compile_file(pkg, src_file, _target, {buildtype: _buildtype, cflags: cached_cflags, verbose: _opts.verbose}) push(support_objects, obj) }) arrfor(c_files, function(file) { var sym_name = shop.c_symbol_for_file(pkg, file) - var dylib = Build.build_module_dylib(pkg, file, _target, {buildtype: _buildtype, extra_objects: support_objects, cflags: cached_cflags}) + var dylib = Build.build_module_dylib(pkg, file, _target, {buildtype: _buildtype, extra_objects: support_objects, cflags: cached_cflags, verbose: _opts.verbose}) if (dylib) { push(results, {file: file, symbol: sym_name, dylib: dylib}) } @@ -847,9 +861,10 @@ Build.generate_module_table = function(modules, output) { // ============================================================================ // Build dynamic libraries for all installed packages -Build.build_all_dynamic = function(target, buildtype) { +Build.build_all_dynamic = function(target, buildtype, opts) { var _target = target || Build.detect_host_target() var _buildtype = buildtype || 'release' + var _opts = opts || {} var packages = shop.list_packages() var results = [] @@ -860,14 +875,14 @@ Build.build_all_dynamic = function(target, buildtype) { // Build core first if (find(packages, function(p) { return p == 'core' }) != null) { - core_mods = Build.build_dynamic('core', _target, _buildtype) + core_mods = Build.build_dynamic('core', _target, _buildtype, _opts) push(results, {package: 'core', modules: core_mods}) } // Build other packages arrfor(packages, function(pkg) { if (pkg == 'core') return - var pkg_mods = Build.build_dynamic(pkg, _target, _buildtype) + var pkg_mods = Build.build_dynamic(pkg, _target, _buildtype, _opts) push(results, {package: pkg, modules: pkg_mods}) }) diff --git a/docs/cli.md b/docs/cli.md index 80466131..3d7f9f9c 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -65,6 +65,7 @@ pit build -b debug # build type: release (default), debug, minsiz pit build --list-targets # list available targets pit build --force # force rebuild pit build --dry-run # show what would be built +pit build --verbose # print resolved flags, commands, cache status ``` ### pit test @@ -330,9 +331,14 @@ pit mcode Apply the full optimization pipeline to a source file and output optimized mcode as JSON. ```bash -pit streamline +pit streamline # full optimized IR as JSON (default) +pit streamline --stats # summary stats per function +pit streamline --ir # human-readable IR +pit streamline --check # warnings only (e.g. high slot count) ``` +Flags can be combined. `--stats` output includes function name, args, slots, instruction counts by category, and nops eliminated. `--check` warns when `nr_slots > 200` (approaching the 255 limit). + ### pit qbe Compile a source file to QBE intermediate language (for native code generation). @@ -367,6 +373,17 @@ Ahead-of-time compile and execute a program natively. pit run_aot ``` +### pit seed + +Regenerate the boot seed files in `boot/`. Seeds are pre-compiled mcode IR (JSON) that bootstrap the compilation pipeline on cold start. They only need regenerating when the pipeline source changes in a way the existing seeds can't compile, or before distribution. + +```bash +pit seed # regenerate all boot seeds +pit seed --clean # also clear the build cache after +``` + +The engine recompiles pipeline modules automatically when source changes (via content-addressed cache). Seeds are a fallback for cold start when no cache exists. + ### Analysis ### pit explain diff --git a/docs/compiler-tools.md b/docs/compiler-tools.md index 8479dfb9..f6217e8b 100644 --- a/docs/compiler-tools.md +++ b/docs/compiler-tools.md @@ -81,9 +81,37 @@ Shows the optimized IR with type annotations. Each instruction is followed by th Runs the full pipeline (tokenize, parse, fold, mcode, streamline) and outputs the optimized IR as JSON. Useful for piping to `jq` or saving for comparison. ```bash -./cell --core . streamline.ce +./cell --core . streamline.ce # full JSON (default) +./cell --core . streamline.ce --stats # summary stats per function +./cell --core . streamline.ce --ir # human-readable IR +./cell --core . streamline.ce --check # warnings only ``` +| Flag | Description | +|------|-------------| +| (none) | Full optimized IR as JSON (backward compatible) | +| `--stats` | Per-function summary: args, slots, instruction counts by category, nops eliminated | +| `--ir` | Human-readable canonical IR (same format as `ir_report.ce`) | +| `--check` | Warnings only (e.g. `nr_slots > 200` approaching 255 limit) | + +Flags can be combined. + +## seed.ce + +Regenerates the boot seed files in `boot/`. These are pre-compiled mcode IR (JSON) files that bootstrap the compilation pipeline on cold start. + +```bash +./cell --core . seed.ce # regenerate all boot seeds +./cell --core . seed.ce --clean # also clear the build cache after +``` + +The script compiles each pipeline module (tokenize, parse, fold, mcode, streamline) and `internal/bootstrap.cm` through the current pipeline, encodes the output as JSON, and writes it to `boot/.cm.mcode`. + +**When to regenerate seeds:** +- Before a release or distribution +- When the pipeline source changes in a way the existing seeds can't compile the new source (e.g. language-level changes) +- Seeds do NOT need regenerating for normal development — the engine recompiles pipeline modules from source automatically via the content-addressed cache + ## ir_report.ce The optimizer flight recorder. Runs the full pipeline with structured logging and outputs machine-readable, diff-friendly JSON. This is the most detailed tool for understanding what the optimizer did and why. diff --git a/docs/packages.md b/docs/packages.md index 154a1274..6e44b203 100644 --- a/docs/packages.md +++ b/docs/packages.md @@ -9,11 +9,11 @@ Packages are the fundamental unit of code organization and sharing in ƿit. ## Package Structure -A package is a directory containing a `pit.toml` manifest: +A package is a directory containing a `cell.toml` manifest: ``` mypackage/ -├── pit.toml # package manifest +├── cell.toml # package manifest ├── main.ce # entry point (optional) ├── utils.cm # module ├── helper/ @@ -23,7 +23,7 @@ mypackage/ └── helpers.cm # private module (internal/ only) ``` -## pit.toml +## cell.toml The package manifest declares metadata and dependencies: @@ -47,7 +47,7 @@ mylib = "/Users/john/work/mylib" When importing with `use()`, ƿit searches in order: 1. **Local package** — relative to package root -2. **Dependencies** — via aliases in `pit.toml` +2. **Dependencies** — via aliases in `cell.toml` 3. **Core** — built-in ƿit modules ```javascript @@ -179,7 +179,7 @@ C files in a package are compiled into per-file dynamic libraries: ``` mypackage/ -├── pit.toml +├── cell.toml ├── render.c # compiled to lib/mypackage/render.dylib └── physics.c # compiled to lib/mypackage/physics.dylib ``` diff --git a/docs/shop.md b/docs/shop.md index ed8a8291..0a94cb16 100644 --- a/docs/shop.md +++ b/docs/shop.md @@ -48,7 +48,7 @@ When `use('path')` is called from a package context, the shop resolves the modul For a call like `use('sprite')` from package `myapp`: 1. **Own package** — `~/.pit/packages/myapp/sprite.cm` and C symbol `js_myapp_sprite_use` -2. **Aliased dependencies** — if `myapp/pit.toml` has `renderer = "gitea.pockle.world/john/renderer"`, checks `renderer/sprite.cm` and its C symbols +2. **Aliased dependencies** — if `myapp/cell.toml` has `renderer = "gitea.pockle.world/john/renderer"`, checks `renderer/sprite.cm` and its C symbols 3. **Core** — built-in core modules and internal C symbols For calls without a package context (from core modules), only core is searched. diff --git a/docs/spec/pipeline.md b/docs/spec/pipeline.md index 1b02dcf1..4cd2bfca 100644 --- a/docs/spec/pipeline.md +++ b/docs/spec/pipeline.md @@ -93,6 +93,25 @@ String constants are interned in a data section. Integer constants are encoded i pit --emit-qbe script.ce > output.ssa ``` +## Boot Seeds + +The `boot/` directory contains pre-compiled mcode IR (JSON) seed files for the pipeline modules: + +``` +boot/tokenize.cm.mcode +boot/parse.cm.mcode +boot/fold.cm.mcode +boot/mcode.cm.mcode +boot/streamline.cm.mcode +boot/bootstrap.cm.mcode +``` + +Seeds are used during cold start (empty cache) to compile the pipeline modules from source. The engine's `load_pipeline_module()` hashes the **source file** content — if the source changes, the hash changes, the cache misses, and the module is recompiled from source using the boot seeds. This means: + +- Editing a pipeline module (e.g. `tokenize.cm`) takes effect on the next run automatically +- Seeds only need regenerating if the pipeline changes in a way the existing seeds can't compile the new source, or before distribution +- Use `pit seed` to regenerate all seeds, and `pit seed --clean` to also clear the build cache + ## Files | File | Role | diff --git a/dump_stream.cm b/dump_stream.cm deleted file mode 100644 index e74a0443..00000000 --- a/dump_stream.cm +++ /dev/null @@ -1,166 +0,0 @@ -// 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 - } -} diff --git a/seed.ce b/seed.ce new file mode 100644 index 00000000..148126fa --- /dev/null +++ b/seed.ce @@ -0,0 +1,116 @@ +// seed.ce — regenerate boot seed files in boot/ +// +// Usage: +// pit seed Regenerate all boot seeds +// pit seed --clean Also clear the build cache after +// +// Seeds are the pre-compiled mcode IR (JSON) files that bootstrap the +// compilation pipeline on cold start. They only need regenerating when: +// - The pipeline source (tokenize, parse, fold, mcode, streamline) changes +// in a way that the boot seeds can't compile the new source +// - You want the seed files to match the current pipeline output +// (e.g. before a release or distribution) +// +// The engine already recompiles pipeline modules from source when their +// content changes (content-addressed cache). Seeds are a fallback for +// cold start when no cache exists. + +var fd = use("fd") +var json = use("json") +var os = use("os") +var shop = use("internal/shop") +var tokenize = use("tokenize") +var parse = use("parse") +var fold = use("fold") +var mcode = use("mcode") +var streamline = use("streamline") + +var clean = false +var i = 0 + +for (i = 0; i < length(args); i++) { + if (args[i] == '--clean') { + clean = true + } else if (args[i] == '--help' || args[i] == '-h') { + print("usage: pit seed [--clean]") + print("") + print(" Regenerate boot seed files in boot/") + print(" --clean Also clear the build cache after") + $stop() + } +} + +var core_dir = shop.get_package_dir('core') +var boot_dir = core_dir + '/boot' +var pipeline_modules = ['tokenize', 'parse', 'fold', 'mcode', 'streamline'] +var generated = 0 +var name = null +var src_path = null +var src = null +var tok = null +var ast = null +var folded = null +var compiled = null +var optimized = null +var mcode_json = null +var out_path = null + +// Regenerate pipeline module seeds +for (i = 0; i < length(pipeline_modules); i++) { + name = pipeline_modules[i] + src_path = core_dir + '/' + name + '.cm' + + if (!fd.is_file(src_path)) { + print('WARNING: source not found: ' + src_path) + continue + } + + print('Seeding ' + name + '.cm ...') + src = text(fd.slurp(src_path)) + tok = tokenize(src, src_path) + ast = parse(tok.tokens, src, src_path, tokenize) + folded = fold(ast) + compiled = mcode(folded) + optimized = streamline(compiled) + mcode_json = json.encode(optimized) + + out_path = boot_dir + '/' + name + '.cm.mcode' + fd.slurpwrite(out_path, stone(blob(mcode_json))) + print(' -> ' + out_path + ' (' + text(length(mcode_json)) + ' bytes)') + generated = generated + 1 +} + +// Regenerate bootstrap.cm seed +var bootstrap_path = core_dir + '/internal/bootstrap.cm' +if (fd.is_file(bootstrap_path)) { + print('Seeding bootstrap.cm ...') + src = text(fd.slurp(bootstrap_path)) + tok = tokenize(src, bootstrap_path) + ast = parse(tok.tokens, src, bootstrap_path, tokenize) + folded = fold(ast) + compiled = mcode(folded) + optimized = streamline(compiled) + mcode_json = json.encode(optimized) + + out_path = boot_dir + '/bootstrap.cm.mcode' + fd.slurpwrite(out_path, stone(blob(mcode_json))) + print(' -> ' + out_path + ' (' + text(length(mcode_json)) + ' bytes)') + generated = generated + 1 +} else { + print('WARNING: bootstrap source not found: ' + bootstrap_path) +} + +print('\nRegenerated ' + text(generated) + ' seed(s)') + +if (clean) { + var build_dir = shop.get_build_dir() + if (fd.is_dir(build_dir)) { + print('Clearing build cache: ' + build_dir) + os.system('rm -rf "' + build_dir + '"') + print('Build cache cleared. Next run will recompile from new seeds.') + } else { + print('No build cache to clear.') + } +} + +$stop() diff --git a/streamline.ce b/streamline.ce index 334a86e4..ae011d32 100644 --- a/streamline.ce +++ b/streamline.ce @@ -1,6 +1,10 @@ -// streamline.ce — run the full compile + optimize pipeline, output JSON +// streamline.ce — run the full compile + optimize pipeline // -// Usage: ./cell --core . streamline.ce +// Usage: +// pit streamline Full optimized IR as JSON (default) +// pit streamline --stats Summary stats per function +// pit streamline --ir Human-readable IR +// pit streamline --check Warnings only (e.g. high slot count) var fd = use("fd") var json = use("json") @@ -9,11 +13,159 @@ var parse = use("parse") var fold = use("fold") var mcode = use("mcode") var streamline = use("streamline") -var filename = args[0] + +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] ") + $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) -print(json.encode(optimized, true)) + +// 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 : "
" +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 : `` + + 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()