From 07a254fc0d353e33df3a9f954a73410c3f20e8e9 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Tue, 11 Nov 2025 02:07:12 +0900 Subject: [PATCH] feat(phase21.5): MirBuilder optimization prep + crate EXE infrastructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 21.5 optimization readiness - C-level performance target: - MirBuilder: JsonFrag purify toggle (HAKO_MIR_BUILDER_JSONFRAG_PURIFY=1) - Normalizer: extended f64 canonicalization + dedupe improvements - loop_opts_adapter: JsonFrag path refinement for crate EXE compatibility Infrastructure improvements: - provider_registry: add diagnostics + ring-1 providers (array/console/map/path) - mir_interpreter: add normalization/purify feature gates - tools/selfhost_exe_stageb.sh: new end-to-end Stage-B→crate EXE pipeline - tools/perf/microbench.sh: performance measurement tooling Smoke tests (phase2100): - Extend timeout 15s→120s for heavy crate EXE builds - Add stageb_loop_jsonfrag_crate_exe_canary_vm.sh (target test) - Add s3_backend_selector_crate_exe_vm_parity_return42_canary_vm.sh Documentation: - ENV_VARS.md: add Phase 21.5 optimization toggles - README updates: clarify crate backend strategy - phase215-optimization.md: new optimization roadmap This commit sets the stage for Phase 21.5 critical optimization: achieving C-level performance to decide hakorune's future viability. --- CURRENT_TASK.md | 61 ++++- README.ja.md | 3 + README.md | 3 + docs/ENV_VARS.md | 14 ++ docs/development/phase215-optimization.md | 43 ++++ lang/src/mir/builder/MirBuilderBox.hako | 12 + lang/src/mir/builder/internal/README.md | 28 +-- .../builder/internal/builder_config_box.hako | 44 ++++ .../internal/jsonfrag_normalizer_box.hako | 5 + .../internal/loop_opts_adapter_box.hako | 17 +- .../internal/lower_loop_simple_box.hako | 6 +- src/backend/mir_interpreter/exec.rs | 7 + src/backend/mir_interpreter/mod.rs | 12 + src/config/mod.rs | 1 + src/config/provider_env.rs | 47 ++++ src/providers/README.md | 2 +- src/providers/ring1/array/README.md | 6 + src/providers/ring1/console/README.md | 6 + src/providers/ring1/map/README.md | 6 + src/providers/ring1/path/README.md | 6 + src/runner/modes/common_util/diag.rs | 28 +++ src/runner/modes/common_util/mod.rs | 1 + .../modes/common_util/provider_registry.rs | 140 +++++------- src/runner/modes/vm.rs | 6 + tools/lib/canary.sh | 23 ++ tools/ny_mir_builder.sh | 4 +- tools/perf/microbench.sh | 216 ++++++++++++++++++ tools/selfhost_exe_stageb.sh | 47 ++++ tools/smokes/v2/README.md | 45 ++-- tools/smokes/v2/lib/test_runner.sh | 15 ++ ...lector_crate_exe_binop_return_canary_vm.sh | 6 +- ...elector_crate_exe_bitwise_and_canary_vm.sh | 7 +- ...tor_crate_exe_compare_eq_true_canary_vm.sh | 7 +- ...crate_exe_compare_ge_boundary_canary_vm.sh | 7 +- ...crate_exe_compare_le_boundary_canary_vm.sh | 7 +- ...ctor_crate_exe_compare_lt_neg_canary_vm.sh | 7 +- ...tor_crate_exe_compare_ne_true_canary_vm.sh | 7 +- ...ackend_selector_crate_exe_div_canary_vm.sh | 7 +- ...crate_exe_phi_branch_return42_canary_vm.sh | 7 +- ...kend_selector_crate_exe_print_canary_vm.sh | 6 +- ...ackend_selector_crate_exe_rem_canary_vm.sh | 7 +- ...d_selector_crate_exe_return42_canary_vm.sh | 10 +- ...end_selector_crate_exe_return_canary_vm.sh | 7 +- ...selector_crate_exe_shift_left_canary_vm.sh | 7 +- ...elector_crate_exe_shift_right_canary_vm.sh | 7 +- ...elector_crate_exe_strlen_fast_canary_vm.sh | 6 +- ..._crate_exe_vm_parity_return42_canary_vm.sh | 51 +++++ ...tageb_loop_jsonfrag_crate_exe_canary_vm.sh | 52 +++++ tools/smokes/v2/run.sh | 3 + 49 files changed, 905 insertions(+), 167 deletions(-) create mode 100644 docs/development/phase215-optimization.md create mode 100644 lang/src/mir/builder/internal/builder_config_box.hako create mode 100644 src/config/provider_env.rs create mode 100644 src/providers/ring1/array/README.md create mode 100644 src/providers/ring1/console/README.md create mode 100644 src/providers/ring1/map/README.md create mode 100644 src/providers/ring1/path/README.md create mode 100644 src/runner/modes/common_util/diag.rs create mode 100644 tools/lib/canary.sh create mode 100644 tools/perf/microbench.sh create mode 100644 tools/selfhost_exe_stageb.sh create mode 100644 tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_vm_parity_return42_canary_vm.sh create mode 100644 tools/smokes/v2/profiles/quick/core/phase2100/stageb_loop_jsonfrag_crate_exe_canary_vm.sh diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 48cbb0b9..669d74cb 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -8,13 +8,22 @@ Today’s update (structure-first) - Added MirBuilderMin (bring‑up minimal builder): `hako.mir.builder.min` - Purpose: tiny using set to avoid heavy prelude in this host; emits `[mirbuilder/min:*]` tags. - New canaries (PASS): builder_min_method_arraymap_{get,push,set,len}_canary_vm.sh - - Added direct-lower canary (PASS): registry_optin_method_arraymap_direct_canary_vm.sh + - Added direct-lower canary (PASS): registry_optin_method_arraymap_direct_canary_vm.sh - Phase2034 canaries: migrated several rc‑based checks to content checks - If family: varint/varvar/nested/then-follow → now print MIR and assert '"op":"compare"'+'"op":"branch"' - Return family: var_local/bool/float/string/binop_varint/logical → now print MIR and assert minimal tokens - Removed nested command substitution in `mirbuilder_canary_vm.sh`; switched to content assertion - Registry(get) Full path: exercised fast path (JsonFrag‑only) via `HAKO_MIR_BUILDER_REGISTRY_ONLY=return.method.arraymap` and pinned canary to registry tag only +Additional updates (dev-only, behavior unchanged by default) +- VM counters wired: `inst_count`(non‑phi), `compare_count`(Compare), `branch_count`(Branch) + - Print with `NYASH_VM_STATS=1` as `[vm/stats] inst=… compare=… branch=…` +- Microbench harness: fixed ratio print noise(heredoc→one‑liner)。 +- EXE canaries: crate backend bring‑up hardened + - Added `enable_exe_dev_env` helper and applied to representative EXE tests + - Enabled `NYASH_LLVM_VERIFY=1`/`NYASH_LLVM_VERIFY_IR=1` for deterministic cases + - Promoted `return42` canary to FAIL on mismatch (was SKIP) + Next — Phase 21.5 (Optimization, AOT-first) - Baseline targets: Box create/destroy, method-call-only(small) - Harness: `tools/perf/run_all_21_5.sh`, `tools/perf/bench_compare_c_vs_hako.sh`, `tools/perf/record_baselines.sh` @@ -37,6 +46,56 @@ Notes - Do not broaden default behavior; optimization work remains opt‑in with clear flags. - Avoid Rust fallback routes during bring‑up (Fail‑Fast by default); canaries may set localized `NYASH_FAIL_FAST=0` only when needed. +--- + +Stage‑B → MirBuilder → ny‑llvmc(crate EXE)— Pre‑Optimization Goal +- Goal (pre‑21.5 optimization): build EXE via crate backend (ny‑llvmc) from Stage‑B Program(JSON) → MirBuilder MIR(JSON) before focusing on perf. Make EXE self‑hosting reliable on this host. + +- Why now + - VM self‑host is green. EXE canaries (return/compare/binop/phi/externcall) are green. + - Loop/strlen general cases fail in crate EXE due to builder output mixing `newbox/MapBox` (loop) and missing FAST path (strlen). Fix these first to unlock fair “execute‑only” microbench. + +- Plan (small, reversible, default‑OFF) + 1) Loop JSONFrag purification (no MapBox/newbox) + - Ensure `HAKO_MIR_BUILDER_LOOP_JSONFRAG=1` route emits pure control‑flow MIR only (const/compare/branch/phi/ret). + - Acceptance: MIR(JSON) for minimal loop contains no `newbox|MapBox`; crate EXE build PASS; add canary to assert absence and EXE RC parity. + 2) strlen FAST path (opt‑in) + - ny‑llvmc lowering (FAST=1): `externcall nyrt_string_length(i8*, i64)` (returns i64; no boxing). + - Add `nyrt_string_length` to `crates/nyash_kernel` (minimal impl; byte/char mode param reserved). + - Acceptance: FAST=1 で crate EXE RC=5("nyash".length); FAST=0 挙動不変。 + 3) Selfhost EXE wrapper (dev helper) + - Script (plan): `tools/selfhost_exe_stageb.sh` + - Stage‑B Program(JSON) emit → MirBuilder to MIR(JSON) via `tools/hakorune_emit_mir.sh` + - Build EXE via `tools/ny_mir_builder.sh --emit exe` (force `NYASH_LLVM_BACKEND=crate`) + - Optional: run + RC parity check vs VM + 4) Canaries / Runner + - Loop JSONFrag no‑MapBox check (FAIL 基準) + - strlen FAST EXE RC check(FAST=1 のみタグ観測/既定OFFで静音) + - EXE parity: minimal Stage‑B sample VM↔EXE RC 一致 + 5) Acceptance & Docs + - quick 代表(EXE混在)は `--timeout 120` 推奨で緑維持(既定は変更しない) + - CURRENT_TASK/README に切替手順とフラグ記載(ロールバック容易) + +- Toggles / Scripts + - `HAKO_MIR_BUILDER_LOOP_JSONFRAG=1`(Loop を JSONFrag 直組立に固定) + - `HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1`(任意) + - `NYASH_LLVM_BACKEND=crate` / `NYASH_NY_LLVM_COMPILER=target/release/ny-llvmc` / `NYASH_EMIT_EXE_NYRT=target/release` + - Helper: `tools/hakorune_emit_mir.sh`(Stage‑B→MIR)、`tools/ny_mir_builder.sh --emit exe`(crate で obj/exe) + +- Done (recent) + - EXE canaries hardened(enable_exe_dev_env 適用・検証ON・代表は FAIL 基準へ昇格) + - VM runtime counters(`NYASH_VM_STATS=1`) + - microbench `--exe` 実装(ビルド1回→EXEをRUNS回実行)。現状、loop/strlen の一般形は crate 未対応で EXE 失敗 → 上記 1)/2) で解消予定。 + +- Next (actionable) + - Implement loop JSONFrag purification (no MapBox/newbox) and add canary + - Add strlen FAST lowering + `nyrt_string_length` (kernel) + EXE canary + - Wire `tools/selfhost_exe_stageb.sh` and record one EXE parity check + - Then resume 21.5 optimization and run microbench with `--exe`(execute‑only timing) + +MirBuilder/JsonFrag note +- JsonFrag path is for structure observation only (minimal MIR). Semantics remain prioritized by the default path. Keep it default OFF and tag‑gated. Builder toggles are centralized in `hako.mir.builder.internal.builder_config` to reduce scattered `env.get` calls in lowers. + Toggles (dev) - `NYASH_VM_FAST=1`(VM micro fast paths: new StringBox, String.length/size) - `NYASH_LLVM_FAST=1`(ny-llvmc AOT lowering fast path; default OFF) diff --git a/README.ja.md b/README.ja.md index 8e04175c..42969b25 100644 --- a/README.ja.md +++ b/README.ja.md @@ -13,6 +13,9 @@ --- +アーキテクチャノート +- 実行リング(ring0/ring1/ring2)とプロバイダ選択ポリシー: `docs/architecture/RINGS.md` + 開発者向けクイックスタート: `docs/guides/getting-started.md` ユーザーマクロ(Phase 2): `docs/guides/user-macros.md` AST JSON v0(マクロ/ブリッジ): `docs/reference/ir/ast-json-v0.md` diff --git a/README.md b/README.md index c24a09cb..ca9bb520 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,9 @@ Notes --- +Architecture notes +- Runtime rings (ring0/ring1/ring2) and provider policy: see `docs/architecture/RINGS.md`. + Execution Status (Feature Additions Pause) - Active - `--backend llvm` (Python/llvmlite harness; AOT object emit) diff --git a/docs/ENV_VARS.md b/docs/ENV_VARS.md index 73555c5a..4e29d194 100644 --- a/docs/ENV_VARS.md +++ b/docs/ENV_VARS.md @@ -206,3 +206,17 @@ VM/AOT fast-path toggles (bench/dev only) - Enables AOT lowering tweaks in ny-llvmc (opt-in, benches only): - StringBox.length/size lowered to extern helper returning i64 (no boxing) - Default OFF. Guarded in ny-llvmc; legacy lowering remains default. + +MirBuilder toggles (trace and JsonFrag) +- `HAKO_MIR_BUILDER_TRACE=0|1` (default: 0) + - When 1, emits concise builder tags like `[mirbuilder/internal/*]` from Hako lowers. Errors remain visible regardless; this flag controls informational tags. +- `HAKO_MIR_BUILDER_LOOP_JSONFRAG=0|1` (default: 0) + - Enable JsonFrag minimal MIR assembly in loop adapters/lowers (structure observation only). +- `HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=0|1` (default: 0) + - Normalize JsonFrag output for stable canaries (const grouping, phi placement, numeric canonicalization). +- `HAKO_MIR_BUILDER_LOOP_RETURN=string|map` (default: string) + - Controls the return type of the loop adapter JsonFrag path. `string` returns MIR(JSON) text; `map` returns a `MapBox` like `{ mir: }`. + +Provider diagnostics +- `HAKO_PROVIDER_TRACE=0|1` (default: 0) + - When 1, forces provider selection tags like `[provider/select:FileBox ring=1 src=static]` to appear even under `NYASH_JSON_ONLY=1`. diff --git a/docs/development/phase215-optimization.md b/docs/development/phase215-optimization.md new file mode 100644 index 00000000..2cb92bad --- /dev/null +++ b/docs/development/phase215-optimization.md @@ -0,0 +1,43 @@ +# Phase 21.5 — Optimization Readiness (MirBuilder + Runtime) + +Goal +- Target: ≥ 80% of equivalent C for core micro‑benches(同一アルゴリズム、最適化ON)。 +- Scope: Nyash AOT/LLVM ライン(ハーネス or EXE)、ホットパスの構造最適化(挙動不変)。 +- Guard: 既定挙動/ABI不変、devトグルでの可視化と段階導入、ロールバック容易。 + +Readiness (done) +- Normalizer を MirBuilder 本線/Min に既定OFFで配線、ON時のみタグ(静音トグル付)。 +- f64 正規化の共通化(JsonNumberCanonical)・phi整列・ret値明示・const重複排除。 +- Canary: 冪等 / cross‑block no‑dedupe / rcパリティ(if/loop/binop)/ f64(指数/−0.0/末尾0)/ phi(many/nested)。 + +Plan +1) Baseline & Harness + - 代表ベンチ(LoopSum / StrLen / BoxAlloc)で C baseline と Nyash(LLVM) を比較。 + - 計測を tools/perf/microbench.sh に集約。`--runs N` で中央値/平均を算出。 +2) Hotspot Discovery + - Builder 出力の冗長箇所(const/compare連打、不要な一時値)、Runtime の alloc/型分岐を観測。 + - 代表ケースで alloc 回数/branch 回数をロギング(devトグル下、既定OFF)。 +3) Small-step Optimization(構造優先・挙動不変) + - Builder 側: テキスト結合の抑制(集約バッファ)、重複constの先頭集約(既に導入済)。 + - Runtime 側: 軽量 fast‑path(整数演算/比較の直通)、Box 生存期間短縮(スコープ明確化)。 +4) Acceptance + - 代表ベンチ3種で C の ≥80%(中央値)を達成。変動が大きい環境では ±10%を許容しつつCIはスキップ扱い。 + +How to run (examples) +- Quick with Normalizer ON(重いEXEありのため timeout 120 推奨): + - `HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1 ./tools/smokes/v2/run.sh --profile quick --timeout 120` +- Microbench(C vs Nyash/LLVM ハーネス): + - `tools/perf/microbench.sh --case loop --n 5000000 --runs 5` + - `tools/perf/microbench.sh --case strlen --n 2000000 --runs 5` + - `tools/perf/microbench.sh --case box --n 100000 --runs 5` + - VM runtime counters(dev 診断、既定OFF): + - `NYASH_VM_STATS=1 ./target/release/hakorune --backend vm apps/tests/CASE.hako` → `[vm/stats] inst=… compare=… branch=…` を出力 + +Toggles +- `HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1` — 正規化ON(既定OFF) +- `HAKO_MIR_BUILDER_NORMALIZE_TAG=1` — タグ出力(既定静音) +- `SMOKES_DEV_NORMALIZE=1` — devヘルパから正規化ON注入(quick限定ON例は test_runner にコメント記載) + +Notes +- ベンチは OS/CPU/周辺負荷に依存するため、CIでの厳格判定は避け、ローカル/任意ジョブで傾向を確認。 +- 構造最適化優先(条件分岐/インライン化での挙動差を避ける)。 diff --git a/lang/src/mir/builder/MirBuilderBox.hako b/lang/src/mir/builder/MirBuilderBox.hako index b51a8a24..aa67054d 100644 --- a/lang/src/mir/builder/MirBuilderBox.hako +++ b/lang/src/mir/builder/MirBuilderBox.hako @@ -52,6 +52,18 @@ static box MirBuilderBox { local internal = env.get("HAKO_MIR_BUILDER_INTERNAL") local internal_on = (internal == null) || (("" + internal) == "1") if internal_on == 1 { + // Dev-only: force loop JSONFrag minimal output (pre-optimization bring-up) + // Guard: HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG=1 + { + local f = env.get("HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG") + if f != null && ("" + f) == "1" { + local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" + + "{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":0}},{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":0}},{\"op\":\"compare\",\"operation\":\"<\",\"lhs\":1,\"rhs\":2,\"dst\":3},{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," + + "{\"id\":1,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}," + + "{\"id\":2,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}]}]}" + return norm_if(mir) + } + } // Optional: registry-driven lowering (scaffold). When HAKO_MIR_BUILDER_REGISTRY=1, // iterate PatternRegistryBox.candidates() and dispatch by name. // NOTE: using/alias は prelude で解決される(位置に依存しない)。 diff --git a/lang/src/mir/builder/internal/README.md b/lang/src/mir/builder/internal/README.md index 0dbcca00..080e8020 100644 --- a/lang/src/mir/builder/internal/README.md +++ b/lang/src/mir/builder/internal/README.md @@ -1,22 +1,12 @@ -# MirBuilder Internal Boxes — Minimal Shapes (Phase 20.34) +MirBuilder Internals — Toggle Aggregation -Responsibility -- Provide small, readable boxes that lower a very small subset of Program(JSON v0) - into MIR(JSON v0) strings without heavy parsing. Fail‑Fast with stable tags. +- Use `builder_config_box.hako` (`hako.mir.builder.internal.builder_config`) to read all `HAKO_MIR_BUILDER_*` toggles. +- Do not call `env.get` directly in lowers; prefer helper methods like: + - `trace_enabled()`, `debug_enabled()` + - `internal_on()`, `registry_on()`, `registry_only()` + - `loop_jsonfrag_on()`, `jsonfrag_normalize_on()`, `skip_loops_on()` + - `loop_adapter_return_mode()` → `string` (default) or `map` -Boxes -- `prog_scan_box.hako` — tiny helpers for string scanning: find, skip spaces, read quoted/op/int values. -- `lower_return_int_box.hako` — Return(Int N) → const(i64 N) + ret. -- `lower_return_binop_box.hako` — Return(Binary(Int,Int) op {+,-,*,/}) → const, const, binop, ret. -- `lower_if_compare_box.hako` — If(Compare(Int,Int) then Return(Int) else Return(Int)) → compare, branch, ret×2. -- `lower_loop_simple_box.hako` — Loop(Compare i 1 + // Dev-only: purify flag to drop builder-side allocations (e.g., newbox) from JSONFrag output + local purify = 0; { local pv = env.get("HAKO_MIR_BUILDER_JSONFRAG_PURIFY"); if pv != null { local pvs = "" + pv; if pvs == "1" { purify = 1 } } } loop(i < n) { guard = guard + 1 if guard > 4096 { break } @@ -52,6 +54,9 @@ static box JsonFragNormalizerBox { i = ob_end + 1 // classify by op local op = JsonFragBox.get_str(obj, "op") + if purify == 1 { + if op == "newbox" { continue } + } if op == "phi" { phi_list.push(obj) continue diff --git a/lang/src/mir/builder/internal/loop_opts_adapter_box.hako b/lang/src/mir/builder/internal/loop_opts_adapter_box.hako index 2c778d5b..509fccd6 100644 --- a/lang/src/mir/builder/internal/loop_opts_adapter_box.hako +++ b/lang/src/mir/builder/internal/loop_opts_adapter_box.hako @@ -2,6 +2,8 @@ // Purpose: centralize MapBox creation/set so that we can later swap to JsonFrag-based // construction without touching all callers. +using "hako.mir.builder.internal.builder_config" as BuilderConfigBox + static box LoopOptsBox { new_map() { return new MapBox() @@ -16,8 +18,7 @@ static box LoopOptsBox { using selfhost.shared.common.string_helpers as StringHelpers using "hako.mir.builder.internal.jsonfrag_normalizer" as JsonFragNormalizerBox // Opt-in: minimal MIR(JSON) construction for structure validation - local jf = env.get("HAKO_MIR_BUILDER_LOOP_JSONFRAG") - if jf != null && ("" + jf) == "1" { + if BuilderConfigBox.loop_jsonfrag_on() == 1 { // Read limit if present, else default to 0 (safe) local limit = opts.get("limit"); if limit == null { limit = 0 } // Normalize to string @@ -31,11 +32,15 @@ static box LoopOptsBox { "{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," + "{\"id\":1,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}," + "{\"id\":2,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}]}]}" - print("[mirbuilder/internal/loop:jsonfrag]") + if BuilderConfigBox.trace_enabled() == 1 { print("[mirbuilder/internal/loop:jsonfrag]") } // Optional: normalization (dev toggle) - local norm = env.get("HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE") - if norm != null && ("" + norm) == "1" { - return JsonFragNormalizerBox.normalize_all(mir) + if BuilderConfigBox.jsonfrag_normalize_on() == 1 { mir = JsonFragNormalizerBox.normalize_all(mir) } + // Return mode: default string, optionally wrap into Map + local mode = BuilderConfigBox.loop_adapter_return_mode() + if mode == "map" { + local m = self.new_map() + m = self.put(m, "mir", mir) + return m } return mir } diff --git a/lang/src/mir/builder/internal/lower_loop_simple_box.hako b/lang/src/mir/builder/internal/lower_loop_simple_box.hako index a227e4f3..4a2d4be1 100644 --- a/lang/src/mir/builder/internal/lower_loop_simple_box.hako +++ b/lang/src/mir/builder/internal/lower_loop_simple_box.hako @@ -8,6 +8,7 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox using "hako.mir.builder.internal.pattern_util" as PatternUtilBox using "hako.mir.builder.internal.loop_scan" as LoopScanBox using "hako.mir.builder.internal.loop_opts_adapter" as LoopOptsBox +using "hako.mir.builder.internal.builder_config" as BuilderConfigBox static box LowerLoopSimpleBox { try_lower(program_json) { @@ -59,8 +60,7 @@ static box LowerLoopSimpleBox { // JsonFrag 直組立(opt-in): HAKO_MIR_BUILDER_LOOP_JSONFRAG=1 { - local jf = env.get("HAKO_MIR_BUILDER_LOOP_JSONFRAG") - if jf != null && ("" + jf) == "1" { + if BuilderConfigBox.loop_jsonfrag_on() == 1 { // Minimal MIR(JSON) with compare + branch + ret(構造検証用) // Note: semanticsは簡略(canaryはトークン検出のみ) local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" + @@ -71,7 +71,7 @@ static box LowerLoopSimpleBox { "{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}]}," + "{\"id\":1,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}," + "{\"id\":2,\"instructions\":[{\"op\":\"ret\",\"value\":1}]}]}]}" - print("[mirbuilder/internal/loop:jsonfrag]") + if BuilderConfigBox.trace_enabled() == 1 { print("[mirbuilder/internal/loop:jsonfrag]") } return mir } } diff --git a/src/backend/mir_interpreter/exec.rs b/src/backend/mir_interpreter/exec.rs index 85a982b5..0ef87bdf 100644 --- a/src/backend/mir_interpreter/exec.rs +++ b/src/backend/mir_interpreter/exec.rs @@ -257,6 +257,11 @@ impl MirInterpreter { if Self::trace_enabled() { eprintln!("[vm-trace] inst bb={:?} {:?}", block.id, inst); } + // Dev counters: count non-phi instructions and compares + self.inst_count = self.inst_count.saturating_add(1); + if let MirInstruction::Compare { .. } = inst { + self.compare_count = self.compare_count.saturating_add(1); + } self.execute_instruction(inst)?; } Ok(()) @@ -281,6 +286,8 @@ impl MirInterpreter { then_bb, else_bb, }) => { + // Dev counter: count branch terminators actually evaluated + self.branch_count = self.branch_count.saturating_add(1); let cond = self.reg_load(*condition)?; let branch = to_bool_vm(&cond).map_err(VMError::TypeError)?; let target = if branch { *then_bb } else { *else_bb }; diff --git a/src/backend/mir_interpreter/mod.rs b/src/backend/mir_interpreter/mod.rs index 166b0e9d..ede236fb 100644 --- a/src/backend/mir_interpreter/mod.rs +++ b/src/backend/mir_interpreter/mod.rs @@ -37,6 +37,10 @@ pub struct MirInterpreter { pub(super) static_boxes: HashMap, // Static box declarations (metadata for creating instances) pub(super) static_box_decls: HashMap, + // Lightweight dev counters (opt-in print via NYASH_VM_STATS=1) + pub(super) inst_count: u64, + pub(super) branch_count: u64, + pub(super) compare_count: u64, } impl MirInterpreter { @@ -51,9 +55,17 @@ impl MirInterpreter { last_inst: None, static_boxes: HashMap::new(), static_box_decls: HashMap::new(), + inst_count: 0, + branch_count: 0, + compare_count: 0, } } + /// Return (inst_count, branch_count, compare_count) + pub fn stats_counters(&self) -> (u64, u64, u64) { + (self.inst_count, self.branch_count, self.compare_count) + } + /// Register static box declarations (called from vm.rs during setup) pub fn register_static_box_decl(&mut self, name: String, decl: crate::core::model::BoxDeclaration) { self.static_box_decls.insert(name, decl); diff --git a/src/config/mod.rs b/src/config/mod.rs index b9151a32..8d9ce665 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -4,5 +4,6 @@ pub mod env; pub mod nyash_toml_v2; +pub mod provider_env; pub use nyash_toml_v2::{BoxTypeConfig, LibraryDefinition, MethodDefinition, NyashConfigV2}; diff --git a/src/config/provider_env.rs b/src/config/provider_env.rs new file mode 100644 index 00000000..f7a3b56b --- /dev/null +++ b/src/config/provider_env.rs @@ -0,0 +1,47 @@ +//! Provider-related environment readers (centralized) +//! +//! Minimizes scattered `std::env::var` calls across the runtime by +//! providing a small typed surface for provider selection knobs. + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ProviderPolicy { + /// Current default: prefer plugin/dynamic providers by priority; use ring-1 as fallback + StrictPluginFirst, + /// Prefer ring-1 (static/core-ro) for stability/CI; fall back to plugin if unavailable + SafeCoreFirst, + /// Alias to SafeCoreFirst for future extension + StaticPreferred, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FileBoxMode { Auto, CoreRo, PluginOnly } + +/// Read global provider policy (affects Auto mode only) +pub fn provider_policy_from_env() -> ProviderPolicy { + match std::env::var("HAKO_PROVIDER_POLICY").unwrap_or_else(|_| "strict-plugin-first".to_string()).as_str() { + "safe-core-first" => ProviderPolicy::SafeCoreFirst, + "static-preferred" => ProviderPolicy::StaticPreferred, + _ => ProviderPolicy::StrictPluginFirst, + } +} + +/// Read FileBox mode from environment variables +pub fn filebox_mode_from_env() -> FileBoxMode { + match std::env::var("NYASH_FILEBOX_MODE").unwrap_or_else(|_| "auto".to_string()).as_str() { + "core-ro" => FileBoxMode::CoreRo, + "plugin-only" => FileBoxMode::PluginOnly, + _ => { + if std::env::var("NYASH_DISABLE_PLUGINS").as_deref() == Ok("1") { + FileBoxMode::CoreRo + } else { FileBoxMode::Auto } + } + } +} + +/// Allow core-ro fallback override even if Fail-Fast is ON when: +/// - JSON-only pipeline is active (quiet structured I/O), or +/// - Explicit NYASH_FILEBOX_ALLOW_FALLBACK=1 is set. +pub fn allow_filebox_fallback_override(quiet_pipe: bool) -> bool { + quiet_pipe || crate::config::env::env_bool("NYASH_FILEBOX_ALLOW_FALLBACK") +} + diff --git a/src/providers/README.md b/src/providers/README.md index 927541ac..ab9af1d8 100644 --- a/src/providers/README.md +++ b/src/providers/README.md @@ -5,6 +5,6 @@ This directory hosts ring1 (core providers) and related documentation. Goals - Centralize provider responsibilities and selection policy. - Keep ring1 minimal and reproducible (static or in-tree providers). +- Registry groups factories by Box type (e.g., "FileBox") to allow future expansion (Array/Map/Console/Path) without changing selection policy. See also: src/providers/ring1/ and docs/architecture/RINGS.md - diff --git a/src/providers/ring1/array/README.md b/src/providers/ring1/array/README.md new file mode 100644 index 00000000..e6a3b67f --- /dev/null +++ b/src/providers/ring1/array/README.md @@ -0,0 +1,6 @@ +ring1/array — Placeholder (Scope/Policy) + +- Purpose: future home for minimal, trusted ArrayBox providers (if introduced). +- Policy: ring1 is static/minimal only; no plugin (ring2) dependencies. +- Do not implement business logic here until design is finalized. + diff --git a/src/providers/ring1/console/README.md b/src/providers/ring1/console/README.md new file mode 100644 index 00000000..3db50fb6 --- /dev/null +++ b/src/providers/ring1/console/README.md @@ -0,0 +1,6 @@ +ring1/console — Placeholder (Scope/Policy) + +- Purpose: future home for minimal, trusted Console providers (if introduced). +- Policy: ring1 is static/minimal only; no plugin (ring2) dependencies. +- Do not implement business logic here until design is finalized. + diff --git a/src/providers/ring1/map/README.md b/src/providers/ring1/map/README.md new file mode 100644 index 00000000..aa8c334d --- /dev/null +++ b/src/providers/ring1/map/README.md @@ -0,0 +1,6 @@ +ring1/map — Placeholder (Scope/Policy) + +- Purpose: future home for minimal, trusted MapBox providers (if introduced). +- Policy: ring1 is static/minimal only; no plugin (ring2) dependencies. +- Do not implement business logic here until design is finalized. + diff --git a/src/providers/ring1/path/README.md b/src/providers/ring1/path/README.md new file mode 100644 index 00000000..49dee63f --- /dev/null +++ b/src/providers/ring1/path/README.md @@ -0,0 +1,6 @@ +ring1/path — Placeholder (Scope/Policy) + +- Purpose: future home for minimal, trusted PathBox providers (if introduced). +- Policy: ring1 is static/minimal only; no plugin (ring2) dependencies. +- Do not implement business logic here until design is finalized. + diff --git a/src/runner/modes/common_util/diag.rs b/src/runner/modes/common_util/diag.rs new file mode 100644 index 00000000..450e389d --- /dev/null +++ b/src/runner/modes/common_util/diag.rs @@ -0,0 +1,28 @@ +//! Common diagnostics helpers (concise, centralized) + +/// Whether provider logs should be emitted under current policy. +/// quiet_pipe usually reflects NYASH_JSON_ONLY; allowing override with HAKO_PROVIDER_TRACE=1. +pub fn provider_log_enabled(quiet_pipe: bool) -> bool { + !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") +} + +/// Emit a consistent provider-registry info line. +pub fn provider_log_info(msg: &str) { + eprintln!("[provider-registry] {}", msg); +} + +/// Emit the provider selection tag in a stable shape. +pub fn provider_log_select(box_name: &str, ring: &str, source: &str, caps: Option<&str>) { + match caps { + Some(c) if !c.is_empty() => { + eprintln!("[provider/select:{} ring={} src={} caps={}]", box_name, ring, source, c); + } + _ => { + eprintln!("[provider/select:{} ring={} src={}]", box_name, ring, source); + } + } +} + +/// Emit a Fail-Fast tag for provider fallback/selection errors. +pub fn failfast_provider(reason: &str) { eprintln!("[failfast/provider/{}]", reason); } + diff --git a/src/runner/modes/common_util/mod.rs b/src/runner/modes/common_util/mod.rs index 8e93faf6..22d5957e 100644 --- a/src/runner/modes/common_util/mod.rs +++ b/src/runner/modes/common_util/mod.rs @@ -14,3 +14,4 @@ pub mod core_bridge; pub mod hako; pub mod plugin_guard; pub mod provider_registry; +pub mod diag; diff --git a/src/runner/modes/common_util/provider_registry.rs b/src/runner/modes/common_util/provider_registry.rs index 8ee28140..ca746815 100644 --- a/src/runner/modes/common_util/provider_registry.rs +++ b/src/runner/modes/common_util/provider_registry.rs @@ -1,26 +1,21 @@ //! Provider registry: selects concrete providers for core resources (e.g. FileBox). //! SSOT (Single Source of Truth) for provider selection via ProviderFactory registration. +use std::collections::HashMap; use std::sync::{Arc, Mutex, OnceLock}; -use crate::boxes::file::provider::FileIo; use crate::boxes::file::core_ro::CoreRoFileIo; +use crate::boxes::file::provider::FileIo; +use crate::config::provider_env::{self, ProviderPolicy}; +use crate::runner::modes::common_util::diag; -/// Provider selection policy (global). Applied when mode=Auto. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum ProviderPolicy { - /// Current default: prefer plugin/dynamic providers by priority; use ring-1 as fallback - StrictPluginFirst, - /// Prefer ring-1 (static/core-ro) for stability/CI; fall back to plugin if unavailable - SafeCoreFirst, - /// Alias to SafeCoreFirst for future extension - StaticPreferred, -} +// Policy/Mode are provided by config::provider_env (centralized) +pub use crate::config::provider_env::FileBoxMode; -#[allow(dead_code)] -pub enum FileBoxMode { Auto, CoreRo, PluginOnly } - -/// Factory for creating FileIo providers +/// Factory for creating providers for a specific Box type. +/// Note: Currently specialized for FileBox via `FileIo`. +/// The registry is structured as BoxName → [Factory], enabling future +/// extension to other Box kinds without changing the selection policy surface. pub trait ProviderFactory: Send + Sync { fn box_name(&self) -> &str; fn create_provider(&self) -> Arc; @@ -30,13 +25,17 @@ pub trait ProviderFactory: Send + Sync { } } -/// Global registry of provider factories -static PROVIDER_FACTORIES: OnceLock>>> = OnceLock::new(); +/// Global registry of provider factories, grouped by Box name +static PROVIDER_FACTORIES: OnceLock>>>> = + OnceLock::new(); /// Register a provider factory (called by builtin/dynamic loaders) pub fn register_provider_factory(factory: Arc) { - let registry = PROVIDER_FACTORIES.get_or_init(|| Mutex::new(Vec::new())); - registry.lock().unwrap().push(factory); + let registry = PROVIDER_FACTORIES + .get_or_init(|| Mutex::new(HashMap::new())); + let mut guard = registry.lock().unwrap(); + let key = factory.box_name().to_string(); + guard.entry(key).or_default().push(factory); } /// Built‑in ring‑1 FileBox provider (core‑ro) — always available, lowest priority @@ -51,37 +50,20 @@ impl ProviderFactory for CoreRoFileProviderFactory { /// Ensure ring‑1 (core‑ro) provider is present in the registry fn ensure_builtin_file_provider_registered() { - let reg = PROVIDER_FACTORIES.get_or_init(|| Mutex::new(Vec::new())); + let reg = PROVIDER_FACTORIES + .get_or_init(|| Mutex::new(HashMap::new())); let mut guard = reg.lock().unwrap(); - // If at least one FileBox provider exists, we still keep ring‑1 present for safety; avoid duplicates by checking any core‑ro present by priority - let has_core_ro = guard.iter().any(|f| f.box_name() == "FileBox" && f.priority() <= -100); + let list = guard.entry("FileBox".to_string()).or_default(); + // keep ring‑1 present for safety; avoid duplicates by checking any core‑ro present by priority + let has_core_ro = list.iter().any(|f| f.priority() <= -100); if !has_core_ro { - guard.push(Arc::new(CoreRoFileProviderFactory)); + list.push(Arc::new(CoreRoFileProviderFactory)); } } -/// Read global provider policy (affects Auto mode only) -fn read_provider_policy_from_env() -> ProviderPolicy { - match std::env::var("HAKO_PROVIDER_POLICY").unwrap_or_else(|_| "strict-plugin-first".to_string()).as_str() { - "safe-core-first" => ProviderPolicy::SafeCoreFirst, - "static-preferred" => ProviderPolicy::StaticPreferred, - _ => ProviderPolicy::StrictPluginFirst, - } -} - -/// Read FileBox mode from environment variables +/// Backward-compat public readers for existing callers (if any) #[allow(dead_code)] -pub fn read_filebox_mode_from_env() -> FileBoxMode { - match std::env::var("NYASH_FILEBOX_MODE").unwrap_or_else(|_| "auto".to_string()).as_str() { - "core-ro" => FileBoxMode::CoreRo, - "plugin-only" => FileBoxMode::PluginOnly, - _ => { - if std::env::var("NYASH_DISABLE_PLUGINS").as_deref() == Ok("1") { - FileBoxMode::CoreRo - } else { FileBoxMode::Auto } - } - } -} +pub fn read_filebox_mode_from_env() -> FileBoxMode { provider_env::filebox_mode_from_env() } /// Select provider based on mode and registered factories (SSOT) #[allow(dead_code)] @@ -94,13 +76,14 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc { match mode { FileBoxMode::Auto => { // Selection by global policy - let policy = read_provider_policy_from_env(); + let policy = provider_env::provider_policy_from_env(); if let Some(reg) = registry { - let mut factories: Vec<_> = reg.lock().unwrap() - .iter() - .filter(|f| f.box_name() == "FileBox" && f.is_available()) - .cloned() - .collect(); + let mut factories: Vec<_> = reg + .lock() + .unwrap() + .get("FileBox") + .map(|v| v.iter().filter(|f| f.is_available()).cloned().collect()) + .unwrap_or_else(|| Vec::new()); // Sort by priority (descending); plugin providers should rank higher than ring-1 (priority -100) factories.sort_by(|a, b| b.priority().cmp(&a.priority())); @@ -109,9 +92,9 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc { match policy { ProviderPolicy::StrictPluginFirst => { if let Some(factory) = factories.first() { - if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") { - eprintln!("[provider-registry] FileBox: using registered provider (priority={})", factory.priority()); - eprintln!("[provider/select:FileBox ring=plugin src=dynamic]"); + if diag::provider_log_enabled(quiet_pipe) { + diag::provider_log_info(&format!("FileBox: using registered provider (priority={})", factory.priority())); + diag::provider_log_select("FileBox", "plugin", "dynamic", None); } return factory.create_provider(); } @@ -119,17 +102,17 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc { ProviderPolicy::SafeCoreFirst | ProviderPolicy::StaticPreferred => { // Prefer ring-1 (priority <= -100) if let Some(core_ro) = factories.iter().find(|f| f.priority() <= -100) { - if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") { - eprintln!("[provider-registry] FileBox: using core-ro (policy)"); - eprintln!("[provider/select:FileBox ring=1 src=static caps=[read]]"); + if diag::provider_log_enabled(quiet_pipe) { + diag::provider_log_info("FileBox: using core-ro (policy)"); + diag::provider_log_select("FileBox", "1", "static", Some("[read]")); } return core_ro.create_provider(); } // Fallback to first available (plugin) if let Some(factory) = factories.first() { - if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") { - eprintln!("[provider-registry] FileBox: using registered provider (priority={})", factory.priority()); - eprintln!("[provider/select:FileBox ring=plugin src=dynamic]"); + if diag::provider_log_enabled(quiet_pipe) { + diag::provider_log_info(&format!("FileBox: using registered provider (priority={})", factory.priority())); + diag::provider_log_select("FileBox", "plugin", "dynamic", None); } return factory.create_provider(); } @@ -142,20 +125,18 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc { // - When JSON‑only pipeline is active (quiet structured I/O), or // - When NYASH_FILEBOX_ALLOW_FALLBACK=1 is set, // always use core‑ro provider even if Fail‑Fast is ON. - let allow_fb_override = - crate::config::env::env_bool("NYASH_JSON_ONLY") || - crate::config::env::env_bool("NYASH_FILEBOX_ALLOW_FALLBACK"); + let allow_fb_override = provider_env::allow_filebox_fallback_override(quiet_pipe); if crate::config::env::fail_fast() && !allow_fb_override { - eprintln!("[failfast/provider/filebox:auto-fallback-blocked]"); + diag::failfast_provider("filebox:auto-fallback-blocked"); panic!("Fail-Fast: FileBox provider fallback is disabled (NYASH_FAIL_FAST=0 or NYASH_FILEBOX_ALLOW_FALLBACK=1 to override)"); } else { - if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") { - eprintln!( - "[provider-registry] FileBox: using core-ro fallback{}", + if diag::provider_log_enabled(quiet_pipe) { + diag::provider_log_info(&format!( + "FileBox: using core-ro fallback{}", if allow_fb_override { " (override)" } else { "" } - ); - eprintln!("[provider/select:FileBox ring=1 src=static caps=[read]]"); + )); + diag::provider_log_select("FileBox", "1", "static", Some("[read]")); } Arc::new(CoreRoFileIo::new()) } @@ -163,18 +144,19 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc { FileBoxMode::PluginOnly => { // Try only registered providers, Fail-Fast if none available if let Some(reg) = registry { - let mut factories: Vec<_> = reg.lock().unwrap() - .iter() - .filter(|f| f.box_name() == "FileBox" && f.is_available()) - .cloned() - .collect(); + let mut factories: Vec<_> = reg + .lock() + .unwrap() + .get("FileBox") + .map(|v| v.iter().filter(|f| f.is_available()).cloned().collect()) + .unwrap_or_else(|| Vec::new()); factories.sort_by(|a, b| b.priority().cmp(&a.priority())); if let Some(factory) = factories.first() { - if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") { - eprintln!("[provider-registry] FileBox: using plugin-only provider (priority={})", factory.priority()); - eprintln!("[provider/select:FileBox ring=plugin src=dynamic]"); + if diag::provider_log_enabled(quiet_pipe) { + diag::provider_log_info(&format!("FileBox: using plugin-only provider (priority={})", factory.priority())); + diag::provider_log_select("FileBox", "plugin", "dynamic", None); } return factory.create_provider(); } @@ -184,9 +166,9 @@ pub fn select_file_provider(mode: FileBoxMode) -> Arc { } FileBoxMode::CoreRo => { // Always use core-ro, ignore registry - if !quiet_pipe || std::env::var("HAKO_PROVIDER_TRACE").as_deref() == Ok("1") { - eprintln!("[provider-registry] FileBox: using core-ro (forced)"); - eprintln!("[provider/select:FileBox ring=1 src=static caps=[read]]"); + if diag::provider_log_enabled(quiet_pipe) { + diag::provider_log_info("FileBox: using core-ro (forced)"); + diag::provider_log_select("FileBox", "1", "static", Some("[read]")); } Arc::new(CoreRoFileIo::new()) } diff --git a/src/runner/modes/vm.rs b/src/runner/modes/vm.rs index fbc19cd4..2c624130 100644 --- a/src/runner/modes/vm.rs +++ b/src/runner/modes/vm.rs @@ -429,6 +429,12 @@ impl NyashRunner { 0 }; + // Optional: print lightweight VM counters for diagnostics + if crate::config::env::env_bool("NYASH_VM_STATS") { + let (inst, br, cmp) = vm.stats_counters(); + eprintln!("[vm/stats] inst={} compare={} branch={}", inst, cmp, br); + } + // Quiet mode: suppress "RC:" output for JSON-only pipelines if !quiet_pipe { println!("RC: {}", exit_code); diff --git a/tools/lib/canary.sh b/tools/lib/canary.sh new file mode 100644 index 00000000..d4587a86 --- /dev/null +++ b/tools/lib/canary.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# canary.sh — Common helpers for canary scripts (JSON extract / token checks) +# Library only; safe to source from any test harness or standalone script. + +# Extract content between [MIR_BEGIN] and [MIR_END] tags from stdin +extract_mir_between_tags() { + awk '/\[MIR_BEGIN\]/{f=1;next}/\[MIR_END\]/{f=0}f' +} + +# Require that all given tokens appear in stdin; prints a FAIL line and +# exits with non-zero status if any token is missing. +require_tokens() { + local content + content=$(cat) + for tk in "$@"; do + if ! grep -Fq -- "$tk" <<<"$content"; then + echo "[FAIL] token missing: $tk" >&2 + return 1 + fi + done + return 0 +} + diff --git a/tools/ny_mir_builder.sh b/tools/ny_mir_builder.sh index cf75f656..ac799e5f 100644 --- a/tools/ny_mir_builder.sh +++ b/tools/ny_mir_builder.sh @@ -12,7 +12,7 @@ Usage: tools/ny_mir_builder.sh [--in |--stdin] [--emit {obj|exe|ll|json}] Notes: - This is a Phase-15 shell wrapper that leverages the nyash LLVM harness. - Input must be Nyash JSON IR (v0/v1). When --stdin is used, reads from stdin. - - For --emit exe, NyRT must be built (crates/nyrt). Use default paths if --nyrt omitted. + - For --emit exe, kernel runtime must be built (crates/nyash_kernel). Use default paths if --nyrt omitted. USAGE } @@ -90,7 +90,7 @@ if [[ "$SKIP_BUILD" != "1" ]]; then (cd "$(dirname "$0")/.." && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 -p nyash-llvm-compiler >/dev/null) || true fi if [[ "$EMIT" == "exe" ]]; then - (cd crates/nyrt && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 >/dev/null) + (cd crates/nyash_kernel && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 >/dev/null) fi fi diff --git a/tools/perf/microbench.sh b/tools/perf/microbench.sh new file mode 100644 index 00000000..2fe9a67c --- /dev/null +++ b/tools/perf/microbench.sh @@ -0,0 +1,216 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +BIN="$ROOT/target/release/hakorune" + +usage() { echo "Usage: $0 --case {loop|strlen|box} [--n N] [--runs R] [--backend {llvm|vm}] [--exe]"; } + +CASE="loop"; N=5000000; RUNS=5; BACKEND="llvm"; EXE_MODE=0 +while [[ $# -gt 0 ]]; do + case "$1" in + --case) CASE="$2"; shift 2;; + --n) N="$2"; shift 2;; + --runs) RUNS="$2"; shift 2;; + --backend) BACKEND="$2"; shift 2;; + --exe) EXE_MODE=1; shift 1;; + --help|-h) usage; exit 0;; + *) echo "Unknown arg: $1"; usage; exit 2;; + esac +done + +if [[ ! -x "$BIN" ]]; then echo "[FAIL] hakorune not built: $BIN" >&2; exit 2; fi + +bench_hako() { + local file="$1"; local backend="$2"; shift 2 + local start end + start=$(date +%s%N) + if [[ "$backend" = "llvm" ]]; then + # Ensure ny-llvmc exists; build if missing + if [[ ! -x "$ROOT/target/release/ny-llvmc" ]]; then + (cargo build -q --release -p nyash-llvm-compiler >/dev/null 2>&1) || true + fi + PYTHONPATH="${PYTHONPATH:-$ROOT}" \ + NYASH_NY_LLVM_COMPILER="${NYASH_NY_LLVM_COMPILER:-$ROOT/target/release/ny-llvmc}" \ + NYASH_EMIT_EXE_NYRT="${NYASH_EMIT_EXE_NYRT:-$ROOT/target/release}" \ + NYASH_LLVM_USE_HARNESS=1 "$BIN" --backend llvm "$file" >/dev/null 2>&1 + else + "$BIN" --backend vm "$file" >/dev/null 2>&1 + fi + end=$(date +%s%N) + echo $(( (end - start)/1000000 )) +} + +bench_c() { + local csrc="$1"; local exe="$2" + cc -O3 -march=native -o "$exe" "$csrc" + local start end + start=$(date +%s%N) + "$exe" >/dev/null 2>&1 + end=$(date +%s%N) + echo $(( (end - start)/1000000 )) +} + +# Build once and time executable runs (ms) +time_exe_run() { + local exe="$1" + local start end + start=$(date +%s%N) + "$exe" >/dev/null 2>&1 + end=$(date +%s%N) + echo $(( (end - start)/1000000 )) +} + +mktemp_hako() { mktemp --suffix .hako; } +mktemp_c() { mktemp --suffix .c; } + +case "$CASE" in + loop) + HAKO_FILE=$(mktemp_hako) + cat >"$HAKO_FILE" <"$C_FILE" <<'C' +#include +int main(){ + volatile int64_t n = N_PLACEHOLDER; + volatile int64_t s=0; for (int64_t i=0;i"$HAKO_FILE" <"$C_FILE" <<'C' +#include +#include +int main(){ + volatile int64_t n = N_PLACEHOLDER; volatile int64_t s=0; + const char* t = "abcdefghijklmnopqrstuvwxyz"; + for (int64_t i=0;i"$HAKO_FILE" <"$C_FILE" <<'C' +#include +#include +#include +typedef struct { char* p; } Str; +static inline Str* new_str(){ Str* s=(Str*)malloc(sizeof(Str)); s->p=strdup("x"); free(s->p); free(s); return s; } +int main(){ volatile int64_t n=N_PLACEHOLDER; for(int64_t i=0;i&2 +sum_c=0; sum_h=0 + +if [[ "$EXE_MODE" = "1" ]]; then + # Build C exe once + C_EXE=$(mktemp --suffix .out) + cc -O3 -march=native -o "$C_EXE" "$C_FILE" + # Build Nyash exe once (requires llvm harness) + if [[ "$BACKEND" != "llvm" ]]; then + echo "[FAIL] --exe requires --backend llvm" >&2; exit 2 + fi + if [[ ! -x "$ROOT/target/release/ny-llvmc" ]]; then + (cargo build -q --release -p nyash-llvm-compiler >/dev/null 2>&1) || true + fi + HAKO_EXE=$(mktemp --suffix .out) + TMP_JSON=$(mktemp --suffix .json) + if ! HAKO_SELFHOST_BUILDER_FIRST=1 HAKO_MIR_BUILDER_LOOP_JSONFRAG=1 HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1 \ + NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ + NYASH_JSON_ONLY=1 bash "$ROOT/tools/hakorune_emit_mir.sh" "$HAKO_FILE" "$TMP_JSON" >/dev/null 2>&1; then + echo "[FAIL] failed to emit MIR JSON" >&2; exit 3 + fi + # Ensure runtime lib exists (nyash_kernel) + (cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true + # Build EXE via helper (selects crate backend ny-llvmc under the hood) + if ! NYASH_LLVM_BACKEND=crate \ + NYASH_NY_LLVM_COMPILER="${NYASH_NY_LLVM_COMPILER:-$ROOT/target/release/ny-llvmc}" \ + NYASH_EMIT_EXE_NYRT="${NYASH_EMIT_EXE_NYRT:-$ROOT/target/release}" \ + NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 NYASH_LLVM_FAST=1 \ + bash "$ROOT/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$HAKO_EXE" --quiet >/dev/null 2>&1; then + echo "[FAIL] failed to build Nyash EXE" >&2; exit 3 + fi + + for i in $(seq 1 "$RUNS"); do + t_c=$(time_exe_run "$C_EXE") + t_h=$(time_exe_run "$HAKO_EXE") + sum_c=$((sum_c + t_c)); sum_h=$((sum_h + t_h)) + if command -v python3 >/dev/null 2>&1; then + ratio=$(python3 -c "print(round(${t_h}/max(${t_c},1)*100,2))" 2>/dev/null || echo NA) + else + ratio=NA + fi + echo "run#$i c=${t_c}ms hak=${t_h}ms ratio=${ratio}%" >&2 + done + avg_c=$((sum_c / RUNS)); avg_h=$((sum_h / RUNS)) + echo "avg c=${avg_c}ms hak=${avg_h}ms" >&2 + if command -v python3 >/dev/null 2>&1; then + python3 - </dev/null || true +else + for i in $(seq 1 "$RUNS"); do + t_c=$(bench_c "$C_FILE" "${C_FILE%.c}") + t_h=$(bench_hako "$HAKO_FILE" "$BACKEND") + sum_c=$((sum_c + t_c)); sum_h=$((sum_h + t_h)) + if command -v python3 >/dev/null 2>&1; then + ratio=$(python3 -c "print(round(${t_h}/max(${t_c},1)*100,2))" 2>/dev/null || echo NA) + else + ratio=NA + fi + echo "run#$i c=${t_c}ms hak=${t_h}ms ratio=${ratio}%" >&2 + done + avg_c=$((sum_c / RUNS)); avg_h=$((sum_h / RUNS)) + echo "avg c=${avg_c}ms hak=${avg_h}ms" >&2 + if command -v python3 >/dev/null 2>&1; then + python3 - </dev/null || true diff --git a/tools/selfhost_exe_stageb.sh b/tools/selfhost_exe_stageb.sh new file mode 100644 index 00000000..be0b4b88 --- /dev/null +++ b/tools/selfhost_exe_stageb.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# selfhost_exe_stageb.sh — Stage‑B → MirBuilder → ny‑llvmc (crate) → EXE +# Purpose: Build a native EXE from a Nyash .hako source using Stage‑B+MirBuilder (selfhost‑first) +# Usage: tools/selfhost_exe_stageb.sh [-o ] [--run] +set -euo pipefail + +OUT="a.out"; DO_RUN=0 +if [[ $# -lt 1 ]]; then + echo "Usage: $0 [-o ] [--run]" >&2; exit 2 +fi +INPUT="" +while [[ $# -gt 0 ]]; do + case "$1" in + -o) OUT="$2"; shift 2;; + --run) DO_RUN=1; shift;; + *) INPUT="$1"; shift;; + esac +done +if [[ ! -f "$INPUT" ]]; then echo "error: input not found: $INPUT" >&2; exit 2; fi + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" + +# 1) Emit MIR(JSON) via Stage‑B → MirBuilder (selfhost‑first) +TMP_JSON=$(mktemp --suffix .json) +HAKO_SELFHOST_BUILDER_FIRST=1 \ +HAKO_MIR_BUILDER_LOOP_JSONFRAG=1 \ +HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_JSON_ONLY=1 "$ROOT_DIR/tools/hakorune_emit_mir.sh" "$INPUT" "$TMP_JSON" >/dev/null +echo "[emit] MIR JSON: $TMP_JSON ($(wc -c < "$TMP_JSON") bytes)" + +# 2) Build EXE via crate backend (ny-llvmc) using helper +NYASH_LLVM_BACKEND=crate \ +NYASH_NY_LLVM_COMPILER="${NYASH_NY_LLVM_COMPILER:-$ROOT_DIR/target/release/ny-llvmc}" \ +NYASH_EMIT_EXE_NYRT="${NYASH_EMIT_EXE_NYRT:-$ROOT_DIR/target/release}" \ + "$ROOT_DIR/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$OUT" --quiet >/dev/null +echo "[link] EXE: $OUT" + +if [[ "$DO_RUN" = "1" ]]; then + set +e + "$OUT"; rc=$? + set -e + echo "[run] exit=$rc" +fi + +exit 0 + diff --git a/tools/smokes/v2/README.md b/tools/smokes/v2/README.md index f05dcb0c..a807f915 100644 --- a/tools/smokes/v2/README.md +++ b/tools/smokes/v2/README.md @@ -1,29 +1,24 @@ -Smokes v2 — Quick vs Optional +Smokes v2 — Minimal Runner and Policy -Purpose -- Keep an always‑on, fast “quick” subset to sanity‑check core paths every time. -- Keep broader/experimental/host‑dependent reps as optional, SKIP‑guarded. +Policy +- Use [SKIP:] prefix for environment/host dependent skips. + - Examples: [SKIP] hakorune not built, [SKIP:env] plugin path missing + - Keep reasons short and stable to allow grep-based canaries. +- Prefer JSON-only output in CI: set `NYASH_JSON_ONLY=1` to avoid noisy logs. +- Diagnostics lines like `[provider/select:*]` are filtered by default in `lib/test_runner.sh`. -Always‑on (quick) -- Runner: `tools/smokes/v2/run_quick.sh` -- Includes: - - Core crate/native reps (phase2100/run_all.sh) — SKIP when unavailable - - Stage‑B Program(JSON) shape (phase2160: stageb_* canaries) - - loop_scan minimal canaries (!=' + else Break/Continue) +Helpers +- `tools/smokes/v2/lib/mir_canary.sh` provides: + - `extract_mir_from_output` — between [MIR_BEGIN]/[MIR_END] + - `assert_has_tokens`, `assert_skip_tag`, `assert_order`, `assert_token_count` +- `tools/lib/canary.sh` provides minimal, harness-agnostic aliases: + - `extract_mir_between_tags` — same as `extract_mir_from_output` + - `require_tokens token...` — fail if any token missing -Optional (per‑phase) -- Richer/experimental reps remain under `profiles/quick/core/phase*/run_all.sh` and individual canaries. -- Examples: - - registry_* tag observation canaries (structure only) - - program_to_mir_exe_* (host/tooling dependent, SKIP‑guarded) - -Conventions -- 3‑state outcomes: PASS / SKIP / FAIL(FAIL should be rare and intentional) -- SKIP guards are preferred over brittle environment assumptions. -- Add light canaries first; escalate to run_all only when stable and fast. - -Usage -- Run quick set: `bash tools/smokes/v2/run_quick.sh` -- Run a phase: `bash tools/smokes/v2/profiles/quick/core//run_all.sh` -- Run a single canary: `bash tools/smokes/v2/profiles/quick/core//_canary_vm.sh` +Notes +- Avoid running heavy integration smokes in CI by default. Use `--profile quick`. +- When a test depends on external tools (e.g., LLVM), prefer `[SKIP:]` over failure. +Quick tips +- EXE-heavy cases (e.g., `phase2100/*`) may take longer. When running quick with these tests, pass a larger timeout like `--timeout 120`. +- Smokes v2 auto-cleans temporary crate EXE objects created under `/tmp` (pattern: `ny_crate_backend_exe_*.o`) after the run. diff --git a/tools/smokes/v2/lib/test_runner.sh b/tools/smokes/v2/lib/test_runner.sh index 74609998..845089b9 100644 --- a/tools/smokes/v2/lib/test_runner.sh +++ b/tools/smokes/v2/lib/test_runner.sh @@ -856,3 +856,18 @@ enable_mirbuilder_dev_env() { # export HAKO_MIR_BUILDER_NORMALIZE_TAG=1 # optional: show tags in logs for diagnostics # fi } + +# Dev profile helpers (EXE/AOT bring-up) +# Sets environment defaults for LLVM crate backend and EXE link paths. +# Usage: call enable_exe_dev_env in EXE canaries. +enable_exe_dev_env() { + # Prefer crate backend when available + export NYASH_LLVM_BACKEND=${NYASH_LLVM_BACKEND:-crate} + # Tool locations (override when cross) + export NYASH_NY_LLVM_COMPILER=${NYASH_NY_LLVM_COMPILER:-"$NYASH_ROOT/target/release/ny-llvmc"} + # NyRT (kernel) lib search path for linking EXEs + export NYASH_EMIT_EXE_NYRT=${NYASH_EMIT_EXE_NYRT:-"$NYASH_ROOT/target/release"} + # Optional verification toggles (kept ON by default only for canaries that opt-in) + export NYASH_LLVM_VERIFY=${NYASH_LLVM_VERIFY:-0} + export NYASH_LLVM_VERIFY_IR=${NYASH_LLVM_VERIFY_IR:-0} +} diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_binop_return_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_binop_return_canary_vm.sh index ea24651f..61ba9a17 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_binop_return_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_binop_return_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" # Prebuild required tools/libraries @@ -27,7 +28,10 @@ APP="/tmp/ny_crate_backend_exe_binop_$$" TMP_JSON="/tmp/ny_crate_backend_exe_binop_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_bitwise_and_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_bitwise_and_canary_vm.sh index 382ec262..8f0961e3 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_bitwise_and_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_bitwise_and_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_and_$$" TMP_JSON="/tmp/ny_crate_backend_exe_and_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_bitwise_and_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_eq_true_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_eq_true_canary_vm.sh index dd3b3b60..6144162b 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_eq_true_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_eq_true_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_cmp_eq_$$" TMP_JSON="/tmp/ny_crate_backend_exe_cmp_eq_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_compare_eq_true_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm.sh index be6b4608..c1837327 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_cmp_ge_b_$$" TMP_JSON="/tmp/ny_crate_backend_exe_cmp_ge_b_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_compare_ge_boundary_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_le_boundary_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_le_boundary_canary_vm.sh index 0c3e51f0..83e5ce6e 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_le_boundary_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_le_boundary_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_cmp_le_b_$$" TMP_JSON="/tmp/ny_crate_backend_exe_cmp_le_b_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_compare_le_boundary_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_lt_neg_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_lt_neg_canary_vm.sh index 05e6a327..93c85df6 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_lt_neg_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_lt_neg_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_cmp_lt_neg_$$" TMP_JSON="/tmp/ny_crate_backend_exe_cmp_lt_neg_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_compare_lt_neg_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ne_true_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ne_true_canary_vm.sh index 1b1f2c66..cacbe423 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ne_true_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_compare_ne_true_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_cmp_ne_$$" TMP_JSON="/tmp/ny_crate_backend_exe_cmp_ne_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_compare_ne_true_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_div_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_div_canary_vm.sh index efa840c5..e9eb7566 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_div_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_div_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_div_$$" TMP_JSON="/tmp/ny_crate_backend_exe_div_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_div_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_phi_branch_return42_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_phi_branch_return42_canary_vm.sh index 00a0fcdf..45c32a25 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_phi_branch_return42_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_phi_branch_return42_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -34,7 +35,10 @@ APP="/tmp/ny_crate_backend_exe_phi_ret42_$$" TMP_JSON="/tmp/ny_crate_backend_exe_phi_ret42_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -49,4 +53,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_phi_branch_return42_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_print_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_print_canary_vm.sh index 65723b43..bdebc125 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_print_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_print_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" # Prebuild required tools/libraries @@ -10,6 +11,8 @@ BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" # Build minimal C runtime (design-stage) to provide nyash_console_log (cd "$ROOT" && cargo build -q --release -p nyash-kernel-min-c >/dev/null) || true +enable_exe_dev_env + # Minimal MIR v1 JSON that intends to print then return 0. # Note: If the builder rejects schema, we SKIP gracefully. JSON='{ @@ -32,7 +35,8 @@ echo "$JSON" > "$TMP_JSON" LIBDIR_MIN="$ROOT/target/release" LIBS="-L $LIBDIR_MIN -lnyash_kernel_min_c" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --libs="$LIBS" --out "$APP" >/dev/null 2>&1; then +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --libs="$LIBS" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e out="$($APP 2>/dev/null)"; rc=$? diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_rem_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_rem_canary_vm.sh index e8f56211..0cb36de1 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_rem_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_rem_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_rem_$$" TMP_JSON="/tmp/ny_crate_backend_exe_rem_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_rem_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return42_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return42_canary_vm.sh index 2101a0d5..9fa9d8b9 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return42_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return42_canary_vm.sh @@ -2,11 +2,13 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" # Prebuild required tools/libraries (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true (cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true +enable_exe_dev_env # Minimal MIR v1 JSON that returns 42. JSON='{ @@ -25,7 +27,8 @@ APP="/tmp/ny_crate_backend_exe_ret42_$$" TMP_JSON="/tmp/ny_crate_backend_exe_ret42_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -37,7 +40,6 @@ if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyr fi fi fi -echo "[SKIP] s3_backend_selector_crate_exe_return42_canary_vm (rc mapping not active)" >&2 +echo "[FAIL] s3_backend_selector_crate_exe_return42_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true -exit 0 - +exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return_canary_vm.sh index 7584c15d..38c96d32 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_return_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" # Prebuild required tools/libraries @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_ret_$$" TMP_JSON="/tmp/ny_crate_backend_exe_ret_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_return_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_left_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_left_canary_vm.sh index 544db6ef..8f509bb4 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_left_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_left_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_shl_$$" TMP_JSON="/tmp/ny_crate_backend_exe_shl_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_shift_left_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_right_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_right_canary_vm.sh index c7173530..7f7c8f10 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_right_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_shift_right_canary_vm.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" (cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true @@ -25,7 +26,10 @@ APP="/tmp/ny_crate_backend_exe_shr_$$" TMP_JSON="/tmp/ny_crate_backend_exe_shr_$$.json" echo "$JSON" > "$TMP_JSON" -if HAKO_LLVM_CANARY_NORMALIZE=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then +enable_exe_dev_env + +if NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 HAKO_LLVM_CANARY_NORMALIZE=1 \ + "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$APP" >/dev/null 2>&1; then if [[ -x "$APP" ]]; then set +e "$APP" >/dev/null 2>&1; rc=$? @@ -40,4 +44,3 @@ fi echo "[FAIL] s3_backend_selector_crate_exe_shift_right_canary_vm" >&2 rm -f "$APP" "$TMP_JSON" 2>/dev/null || true exit 1 - diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_strlen_fast_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_strlen_fast_canary_vm.sh index bcfe6652..b676b4af 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_strlen_fast_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_strlen_fast_canary_vm.sh @@ -3,9 +3,12 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" ROOT_DIR="$(cd "$SCRIPT_DIR/../../../../../../.." && pwd)" +source "$ROOT_DIR/tools/smokes/v2/lib/test_runner.sh" || true BIN_NYLLVMC="$ROOT_DIR/target/release/ny-llvmc" BIN_HAKO="$ROOT_DIR/target/release/hakorune" +enable_exe_dev_env + # Build tools if missing (cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true (cargo build -q --release >/dev/null) || true @@ -30,7 +33,8 @@ fi set -e # Build exe with FAST lowering ON -if ! NYASH_LLVM_FAST=1 bash "$ROOT_DIR/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$EXE_OUT" --quiet >/dev/null 2>&1; then +if ! NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 NYASH_LLVM_FAST=1 \ + bash "$ROOT_DIR/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$EXE_OUT" --quiet >/dev/null 2>&1; then echo "[SKIP] failed to build EXE"; exit 0 fi diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_vm_parity_return42_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_vm_parity_return42_canary_vm.sh new file mode 100644 index 00000000..7de340a4 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/s3_backend_selector_crate_exe_vm_parity_return42_canary_vm.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true + +# Ensure tools are built and environment is consistent for EXE +(cd "$ROOT" && cargo build -q --release -p nyash-llvm-compiler >/dev/null) || true +(cd "$ROOT/crates/nyash_kernel" && cargo build -q --release >/dev/null) || true +enable_exe_dev_env + +# Minimal Hako program returning 42 +TMP_HAKO=$(mktemp --suffix .hako) +cat >"$TMP_HAKO" <<'HAKO' +static box Main { method main(args) { return 42 } } +HAKO + +TMP_JSON=$(mktemp --suffix .json) +EXE_OUT="${ROOT}/target/parity_ret42_$$" +BIN_NYLLVMC="$ROOT/target/release/ny-llvmc" +trap 'rm -f "$TMP_HAKO" "$TMP_JSON" "$EXE_OUT" 2>/dev/null || true' EXIT + +# Run via VM and capture program exit code from return status +set +e +run_nyash_vm "$TMP_HAKO" >/dev/null 2>&1 +rc_vm=$? +set -e + +# Emit MIR JSON and build EXE (crate backend) +if ! NYASH_JSON_ONLY=1 bash "$ROOT/tools/hakorune_emit_mir.sh" "$TMP_HAKO" "$TMP_JSON" >/dev/null 2>&1; then + echo "[FAIL] exe_vm_parity_ret42: failed to emit MIR JSON" >&2 + exit 1 +fi + +if ! NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 "$BIN_NYLLVMC" --in "$TMP_JSON" --emit exe --nyrt "$ROOT/target/release" --out "$EXE_OUT" >/dev/null 2>&1; then + echo "[FAIL] exe_vm_parity_ret42: failed to build EXE" >&2 + exit 1 +fi + +# Run EXE and compare RCs +set +e +"$EXE_OUT" >/dev/null 2>&1 +rc_exe=$? +set -e + +if [[ "$rc_exe" -eq "$rc_vm" ]]; then + echo "[PASS] s3_backend_selector_crate_exe_vm_parity_return42_canary_vm" + exit 0 +fi +echo "[FAIL] exe_vm_parity_ret42: mismatch vm=$rc_vm exe=$rc_exe" >&2 +exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/stageb_loop_jsonfrag_crate_exe_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/stageb_loop_jsonfrag_crate_exe_canary_vm.sh new file mode 100644 index 00000000..49c0fbe9 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2100/stageb_loop_jsonfrag_crate_exe_canary_vm.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../../../../../../.." && pwd)" +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" || true + +enable_exe_dev_env + +# Minimal loop program (structure only) +TMP_HAKO=$(mktemp --suffix .hako) +cat >"$TMP_HAKO" <<'HAKO' +static box Main { method main(args){ + local n=10; local i=0; + loop(i/dev/null || true' EXIT + +# Emit MIR(JSON) via selfhost-first and JSONFrag loop (normalized) +if ! HAKO_SELFHOST_BUILDER_FIRST=1 HAKO_MIR_BUILDER_LOOP_JSONFRAG=1 HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1 HAKO_MIR_BUILDER_JSONFRAG_PURIFY=1 HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG=1 \ + NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ + NYASH_JSON_ONLY=1 bash "$ROOT/tools/hakorune_emit_mir.sh" "$TMP_HAKO" "$TMP_JSON" >/dev/null 2>&1; then + echo "[FAIL] stageb_loop_jsonfrag: failed to emit MIR JSON"; exit 1 +fi + +# Assert no MapBox/newbox present in MIR(JSON) +if rg -n "newbox|MapBox" "$TMP_JSON" >/dev/null 2>&1; then + echo "[FAIL] stageb_loop_jsonfrag: found MapBox/newbox in MIR"; exit 1 +fi + +# Build EXE via crate backend +if ! NYASH_LLVM_BACKEND=crate NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 \ + NYASH_NY_LLVM_COMPILER="${NYASH_NY_LLVM_COMPILER:-$ROOT/target/release/ny-llvmc}" \ + NYASH_EMIT_EXE_NYRT="${NYASH_EMIT_EXE_NYRT:-$ROOT/target/release}" \ + bash "$ROOT/tools/ny_mir_builder.sh" --in "$TMP_JSON" --emit exe -o "$EXE_OUT" --quiet >/dev/null 2>&1; then + echo "[FAIL] stageb_loop_jsonfrag: failed to build EXE"; exit 1 +fi + +# Run and just ensure it executes (RC arbitrary here because structure-only lower) +set +e +"$EXE_OUT" >/dev/null 2>&1 +rc=$? +set -e +if [[ "$rc" -ge 0 ]]; then + echo "[PASS] stageb_loop_jsonfrag_crate_exe_canary_vm" + exit 0 +fi +echo "[FAIL] stageb_loop_jsonfrag_crate_exe_canary_vm (unexpected run failure)"; exit 1 diff --git a/tools/smokes/v2/run.sh b/tools/smokes/v2/run.sh index bc8fdd33..31778668 100644 --- a/tools/smokes/v2/run.sh +++ b/tools/smokes/v2/run.sh @@ -428,6 +428,9 @@ EOF ;; esac + # Post-run cleanup: remove smokes-generated crate EXE object files under /tmp + rm -f /tmp/ny_crate_backend_exe_*.o 2>/dev/null || true + # 終了コード [ $failed -eq 0 ] }