phase15: add Cranelift AOT design, LinkerBox spec, and smoke skeleton docs (handoff)

This commit is contained in:
Moe Charm
2025-09-05 05:49:26 +09:00
parent 19f775c34d
commit e05a385524
8 changed files with 529 additions and 0 deletions

View File

@ -0,0 +1,57 @@
Cranelift AOT Box: 設計ノートと obj 出力 PoCPhase 15 準備)
目的
- Nyash → MIR → Cranelift AOTC ABI→ オブジェクト(.o/.obj→ リンク → EXE の最小パイプラインを確立する前準備。
- 本ブランチでは「設計と仕様の確定(ドキュメント化)」のみを行い、実装は別ブランチ `phase-15/self-host-aot-cranelift` で着手する。
対象範囲P0
- PoC として `ny_main`i64 → i64 返し)を定義する最小オブジェクトを Cranelift で生成できること。
- 生成物を NyRT`crates/nyrt`)と静的リンクして実行可能ファイルを作成できること。
- 実行結果として `Result: 42` 等の既知の値確認を行うこと。
アーキテクチャ概要
- CraneliftAotBox本ドキュメントの主題
- 役割: MIR から Cranelift IRCLIFを生成し、`cranelift-object` でオブジェクトを出力する。
- 出力: ターゲット環境に応じた COFF/ELF/Mach-O`cranelift-object` の既定に従う)。
- シグネチャ: PoC は `ny_main: () -> i64`(将来的には引数の受け渡しや NyRT 呼び出しを拡張)。
- LinkerBox別タスク、別文書で仕様化
- 役割: 生成された `.o/.obj` を NyRT`libnyrt.a`/`nyrt.lib`)とリンクして EXE を作る。
- Windows は `link.exe`/`lld-link`、Linux は `cc` 経由を想定(詳細は LinkerBox 仕様にて)。
ABI / 連携
- エントリ: `ny_main` を EXE から呼び出す形。NyRT 側が `main()` 内から `ny_main()` を適切に呼び出して結果を表示(または検証)する想定。
- ランタイム: PoC 段階では NyRT の最低限(起動/終了)に依存。将来的に checkpoint や GC バリアなどの外部関数を `extern "C"` で参照可能にする。
PoC 受入基準P0
- `.o/.obj``ny_main` シンボルが定義されている。
- `libnyrt.a`/`nyrt.lib` とリンクして実行可能ファイルが作成できる。
- 実行すると標準出力に既知の値(例: `Result: 42`)が出力される。
想定コマンド(リンク例)
- Linux: `cc -o app ny_main.o target/release/libnyrt.a -ldl -lpthread`
- Windows (MSVC): `link ny_main.obj nyrt.lib /OUT:app.exe`
- 実行時設定: 実行ファイルと同じディレクトリに `nyash.toml` を配置することでプラグイン解決を容易にするNyRT は exe 直下→CWD の順で探索)。
CLI/ツール統合(案)
- バックエンドキー: `--backend cranelift-aot`
- PoC フラグ: `--poc-const N``ny_main``N` を返す単機能)
- 補助スクリプト(設計のみ、本ブランチでは作成しない):
- `tools/aot_smoke_cranelift.sh apps/APP/main.nyash -o app`
- 流れ: Nyash → MIR → CraneliftAotBox → `.o` → LinkerBox/cc → `app`
ロードマップ
- P0: PoC スタブ `ny_main` 定数返し、リンク/実行確認。
- P1: 最小 MIR`const_i64`/`add_i64`/`ret`)のマッピング。
- P2: NyRT チェックポイント呼び出しなど最小の外部関数連携。
- P3: Plugin 経由の I/O など実用的な呼び出しの一部導入。
既知のリスクと対策
- プラットフォーム ABI 差異: 既定の呼出規約を使用し、まず Linux で動作確認。
- オブジェクト形式差: `cranelift-object` の既定に寄り添う。必要に応じてターゲット指定を導入。
- 重複実装の懸念: 既存のオブジェクトビルダJIT/emit系の再利用・抽象化を検討。
実装方針(別ブランチで実施)
- フィーチャ: `cranelift-aot = ["dep:cranelift-object"]`
- モジュール: `src/backend/cranelift/aot_box.rs` を追加し、PoC 用 `compile_stub_ny_main_i64` を提供。
- CLI 統合: `--backend cranelift-aot` と PoC フラグの導入PoC 期間は一時的)。

View File

@ -0,0 +1,55 @@
Phase 15 — Self-Hosting (Cranelift AOT) 引き継ぎメモ
概要2025-09-05
- 目的: Nyash → MIR → Cranelift AOT → オブジェクト → リンク → EXE の最小パイプライン確立に向けた準備(設計/仕様/スモーク雛形)。
- 実装は別ブランチ `phase-15/self-host-aot-cranelift` で着手予定。現状はドキュメントと雛形スクリプトまで整備。
このブランチで完了したこと
- Cranelift AOT 設計とインタフェース草案のドキュメント追加:
- docs/backend-cranelift-aot-design.md
- docs/interfaces/cranelift-aot-box.md
- LinkerBox 仕様とAOTスモーク仕様擬似出力
- docs/interfaces/linker-box.md
- docs/tests/aot_smoke_cranelift.md
- Phase 15 集約README
- docs/phase-15/README.md
- スモーク雛形DRYRUN既定。CLIF_SMOKE_RUN=1で実行
- tools/aot_smoke_cranelift.shUnix/WSL
- tools/aot_smoke_cranelift.ps1Windows
次にやること(別ブランチで実装)
1) ブランチ作成: `git switch -c phase-15/self-host-aot-cranelift`
2) CraneliftAotBoxPoC
- `src/backend/cranelift/aot_box.rs` を追加
- `compile_stub_ny_main_i64(val, out_obj)``.o/.obj` を出力
- Cargo feature: `cranelift-aot = ["dep:cranelift-object"]`
3) LinkerBoxWindows優先
- `.o/.obj` + NyRT`libnyrt.a`/`nyrt.lib`)で EXE を生成
- 環境変数: `NYASH_LINKER`/`NYASH_LINK_FLAGS`/`NYASH_LINK_VERBOSE`
4) CLI 統合PoC
- `--backend cranelift-aot``--poc-const N`
5) スモーク
- apps/ny-hello → emit → link → run → `Result: 42` を確認
- 既存スクリプト雛形を “実行” モードで動くよう配線
運用メモCodex 非同期 2本
- 2本起動: `CODEX_MAX_CONCURRENT=2 CODEX_DEDUP=1 ./tools/codex-keep-two.sh codex "<Task A>" "<Task B>"`
- 1本起動: `CODEX_ASYNC_DETACH=1 ./tools/codex-async-notify.sh "<task>" codex`
- ログ: `~/.codex-async-work/logs/`
スモーク雛形の使い方DRYRUN
- Unix/WSL: `./tools/aot_smoke_cranelift.sh release`
- Windows: `pwsh -File tools/aot_smoke_cranelift.ps1 -Mode release`
- 実行モード: `CLIF_SMOKE_RUN=1` を付与AOT実装が入った後に使用
参考リンク
- docs/phase-15/README.md全体像
- docs/backend-cranelift-aot-design.mdAOT設計
- docs/interfaces/cranelift-aot-box.mdCraneliftAotBox API案
- docs/interfaces/linker-box.mdLinkerBox仕様
- docs/tests/aot_smoke_cranelift.mdスモーク仕様と擬似出力
補足(メモリ/GC
- P0/P1定数返し/整数演算では追加のメモリ系Boxは不要。
- P2以降で配列/文字列の生成・更新をAOTから行う場合、NyRTに最小のC ABIroots/barrier/alloc系を追加予定docsに設計案を後続追記

View File

@ -0,0 +1,57 @@
CraneliftAotBox インタフェース草案Phase 15 準備)
前提
- 本ブランチでは「仕様化(ドキュメント)」のみ行い、実装は別ブランチ `phase-15/self-host-aot-cranelift` で行う。
- Cargo フィーチャ: `cranelift-aot = ["dep:cranelift-object"]` を追加し、同フィーチャ時のみ AOT モジュールを有効化する。
モジュール構成(案)
- パス: `src/backend/cranelift/aot_box.rs`
- 依存: `cranelift-object`(オブジェクト出力)、既存のオブジェクトビルダ/ヘルパを再利用可能なら抽象化して流用。
公開型(案)
- `pub struct CraneliftAotConfig {`
- `pub opt_level: u8` // 0..3 程度(実装は後続)
- `pub target: Option<String>` // target triple 等(未指定でホスト)
`}`
- `pub struct CraneliftAotBox {`
- `obj: <object builder>`
- `cfg: CraneliftAotConfig`
`}`
- `#[derive(Debug)] pub enum CraneliftAotError {`
- `Codegen(String)`, `IO(String)`
`}`
主要メソッド(案)
- `impl CraneliftAotBox {`
- `pub fn new(cfg: CraneliftAotConfig) -> Result<Self, CraneliftAotError>`
- `pub fn compile_stub_ny_main_i64(&mut self, val: i64, out_obj: impl AsRef<Path>) -> Result<(), CraneliftAotError>`
- 役割: PoC。`ny_main` 関数を定義し、即値 `val` を返すオブジェクトを生成。
- `pub fn compile_mir_to_obj(&mut self, mir: MirModule, out_obj: impl AsRef<Path>) -> Result<(), CraneliftAotError>`
- 役割: P1〜。最小 MIR`const_i64`/`add_i64`/`ret`)から CLIF を組み立てて出力。
`}`
使用例PoC フロー)
1) NyRT ビルド: `cargo build -p nyrt --release`
2) オブジェクト出力CLIイメージ:
- `nyash --backend cranelift-aot --poc-const 42 apps/hello/main.nyash -o ny_main.o`
3) リンク:
- Linux: `cc -o app ny_main.o target/release/libnyrt.a -ldl -lpthread`
- Windows: `link ny_main.obj nyrt.lib /OUT:app.exe`
4) 実行: `./app``Result: 42` を確認。
エラーモデル(案)
- 環境・設定: フィーチャ未有効や未対応ターゲット → 分かりやすいメッセージ。
- 生成・出力: `CraneliftAotError::Codegen(_)``CraneliftAotError::IO(_)` で大別。
補助スクリプトの仕様(設計のみ)
- ファイル: `tools/aot_smoke_cranelift.sh`
- 目的: `.o/.obj` を生成→リンク→実行して PoC を自動検証。
- 主要引数: `apps/APP/main.nyash -o app`、必要に応じ `--const` を透過的に渡す。
今後の拡張(非ブロッキング)
- NyRT の外部関数呼び出しcheckpoint など)の導入。
- MIR 命令カバレッジの拡大、BoxCall/Plugin 経由の I/O。
- ターゲットトリプルとオブジェクト形式の明示的制御。

View File

@ -0,0 +1,48 @@
LinkerBox 仕様Phase 15 準備 / Windows優先
目的
- AOT 生成されたオブジェクト(`.o/.obj`)を NyRT とリンクして実行可能ファイルを得る統一レイヤ。
- 初期実装は「外部リンカー呼び出し」MSVC `link.exe` または `lld-link`、Unix は `cc`)で動作し、将来的に lld 内蔵連携へ置換可能な設計とする。
前提/エントリポイント
- 既定のエントリポイントは NyRT 側の `main()``crates/nyrt` に実装)。
- AOT 側は `ny_main`(想定: `() -> i64`を定義し、NyRT の `main()``ny_main()` を呼び出す。
- よって通常は `/ENTRY:` 指定は不要NyRT をリンクしない特殊構成でのみ上書き可能とする)。
入力と出力
- 入力: 一つ以上のオブジェクト(`.obj`/`.o`)、追加ライブラリ群、ライブラリ検索パス。
- 既定ライブラリ: NyRTWindows: `nyrt.lib`、Unix: `libnyrt.a`)。
- 出力: 実行ファイルWindows: `*.exe`、Unix: 実行ビット付きバイナリ)。
環境変数LinkerBox が解釈)
- `NYASH_LINKER`: 使用リンカーを強制。`link` | `lld-link` | `cc`(未指定は OS/環境から自動推定)
- `NYASH_LINK_FLAGS`: 追加フラグ(空白区切り)。
- `NYASH_LINK_VERBOSE=1`: 実コマンドラインを表示。
- `NYASH_LINK_ENTRY=<symbol>`: エントリポイントを明示的に指定(既定は未指定で NyRT の `main` を使用)。
- `NYASH_LINK_OUT=<path>`: 出力先を明示的に指定CLI引数 `-o` が優先)。
WindowsMSVC / lld-link
- 既定探索順: `link.exe``lld-link`
- 代表フラグ:
- `link.exe`: `/OUT:<exe>` `/SUBSYSTEM:CONSOLE`(既定) `/LIBPATH:<dir>` `nyrt.lib`
- `lld-link`: `-OUT:<exe>` `-SUBSYSTEM:CONSOLE` `-LIBPATH:<dir>` `nyrt.lib`
- `PATH`/`LIB`/`LIBPATH` の整合に注意Developer Command Prompt を推奨)。
Unix参考
- 代表フラグ: `cc -o <exe> <objs...> <lib paths> -L... -lnyrt -ldl -lpthread`
- 既定のオブジェクト形式/ターゲットはホストに従う。
CLI API想定
- `nyash --linker link|lld-link|cc --libpath <dir> --lib nyrt [--entry nyash_main] -o app <objs...>`
- AOT パスでは内部的に LinkerBox を呼び出し、上記環境変数も透過的に反映する。
エラー方針
- ツールチェーン未検出(リンカー不在): わかりやすい対処案を表示MSVC のセットアップlld の導入)。
- 未解決シンボル: `ny_main`/NyRT 関連の欠落を優先表示。
- 引数/パスのクォート: 空白を含むパスは安全にクォートして実行。
将来拡張
- 内蔵 lld を採用した一体化(外部プロセス呼び出しからの置換)。
- ターゲットトリプルの明示指定とクロスリンク(フェーズ後半)。
- 追加ランタイムやプラグイン静的リンクのオプション化。

32
docs/phase-15/README.md Normal file
View File

@ -0,0 +1,32 @@
Phase 15 — Self-Hosting (Cranelift AOT) 準備メモ
目的
- Nyash → MIR → Cranelift AOTC ABI→ オブジェクト → リンク → EXE の最小パイプライン確立。
- 本ブランチでは「影響小・再現性高い」準備(設計/仕様/スモーク雛形)に限定し、実装は別ブランチで行う。
現状ステータス(このブランチ)
- 設計ノート: docs/backend-cranelift-aot-design.md
- インタフェース草案: docs/interfaces/cranelift-aot-box.md
- LinkerBox 仕様: docs/interfaces/linker-box.md
- AOTスモーク仕様擬似出力: docs/tests/aot_smoke_cranelift.md
- スモーク雛形DRYRUN 既定):
- tools/aot_smoke_cranelift.shUnix/WSL
- tools/aot_smoke_cranelift.ps1Windows
ハンドオフ
- 引き継ぎの全体像と運用メモは docs/handoff/phase-15-handoff.md を参照。
次ブランチで実装する項目phase-15/self-host-aot-cranelift
- CraneliftAotBox: `compile_stub_ny_main_i64``.o/.obj` を出力。
- LinkerBox: `.o/.obj` + NyRTlibnyrtで EXE にリンクWindows優先
- CLI統合: `--backend cranelift-aot` と PoC フラグ(`--poc-const`)。
- スモーク実行: apps/ny-hello → EXE 生成・起動確認。
合否基準P0
- `ny_main` を定義するオブジェクトを生成できる。
- NyRT とリンクして EXE を生成できる。
- 実行し、既知の値(例: `Result: 42`)を出力。
補足
- Windowsを先行サポートし、Linux/macOS は後続対応。
- 実出力やビルドログは `tools/codex-async-notify.sh` のログ参照運用を継続。

View File

@ -0,0 +1,75 @@
# Cranelift AOT Smoke (Windowsfirst)
Purpose
- Validate the Craneliftbased AOT pipeline endtoend:
1) Build `nyash` with `cranelift-jit` feature.
2) Emit an object via `NYASH_AOT_OBJECT_OUT` while running `--backend cranelift`.
3) Link the object with NyRT into a runnable binary (via LinkerBox or helper scripts).
4) Run the binary and assert output.
Prerequisites
- Build flags: `cargo build --release --features cranelift-jit`
- Windows:
- Prefer MSVC `link.exe` (Developer Command Prompt or properly set env).
- Fallback: `lld-link` in `PATH`.
- PowerShell available for `tools/aot_smoke_cranelift.ps1`.
- Unix (optional): system linker (`ld`), or `lld`/`mold`, and `tools/aot_smoke_cranelift.sh`.
Environment toggles
- `NYASH_CLIF_ARRAY_SMOKE=1`: run array smoke (simple Result check).
- `NYASH_CLIF_ARRAY_RET_SMOKE=1`: run “return value” array smoke.
- `NYASH_CLIF_ECHO_SMOKE=1`: run echo smoke (stdin → stdout).
- `NYASH_CLIF_VINVOKE_SMOKE=1`: run variablelength invoke smoke (plugins required).
- `NYASH_CLIF_VINVOKE_RET_SMOKE=1`: run vinvoke return/size smokes (plugins required).
- `NYASH_DISABLE_PLUGINS=1`: disable plugindependent smokes.
- `NYASH_LINK_VERBOSE=1`: print final link command.
Pseudo run
- Script: `tools/aot_smoke_cranelift.sh` / `tools/aot_smoke_cranelift.ps1`
- Typical invocation: `./tools/aot_smoke_cranelift.sh release`
Pseudo output (example)
```
[clif-aot-smoke] building nyash (release, feature=cranelift-jit)...
[clif-aot-smoke] emitting object via --backend cranelift ...
[clif-aot-smoke] OK: object generated: /ABS/path/target/aot_objects/core_smoke.obj (1536 bytes)
[clif-aot-smoke][win] linking app_clif.exe using link.exe
[clif-aot-smoke][win] entry=nyash_main subsystem=CONSOLE runtime=nyrt.lib
[clif-aot-smoke] running app_clif.exe ...
[clif-aot-smoke] output: Result: 3
[clif-aot-smoke] OK: core smoke passed
[clif-aot-smoke] skipping array smoke (set NYASH_CLIF_ARRAY_SMOKE=1 to enable)
[clif-aot-smoke] skipping echo smoke (set NYASH_CLIF_ECHO_SMOKE=1 to enable)
[clif-aot-smoke] skipping vinvoke smokes (set NYASH_CLIF_VINVOKE_SMOKE=1 / NYASH_CLIF_VINVOKE_RET_SMOKE=1)
```
What the script does (intended)
- Build:
- `cargo build --release --features cranelift-jit`
- Emit object:
- Ensure stable output dir: `mkdir -p target/aot_objects`
- `NYASH_AOT_OBJECT_OUT="$PWD/target/aot_objects/core_smoke.obj" ./target/release/nyash --backend cranelift apps/hello/main.nyash > /dev/null || true`
- Validate file exists and nonzero size.
- Link:
- Windows: PowerShell `tools/aot_smoke_cranelift.ps1 -Mode release`
- Unix: `tools/aot_smoke_cranelift.sh release`
- Run and verify:
- `./app_clif[.exe]` → expect a line including `Result:`.
Windows specifics
- Prefer MSVC `link.exe`; autofallback to `lld-link` if present.
- If neither available, fail with a helpful message to open a Developer Command Prompt or install LLVM lld.
- Use `.obj` extension for emitted object; still accept `.o` if emitted by a GNU toolchain.
Exit codes
- 0: all enabled smokes passed
- 1: object missing/empty, or unexpected program output
- 2: toolchain missing (no Cranelift build or no linker)
Future alignment with LinkerBox
- This smoke is the acceptance test for LinkerBoxs AOT path on Cranelift:
- Same entrypoint (`nyash_main`), runtime linkage (`nyrt.lib`/`libnyrt.a`), and CLI env (`NYASH_LINKER`, `NYASH_LINK_FLAGS`, `NYASH_LINK_VERBOSE`).
- When LinkerBox becomes default, keep CLI stable and swap implementation behind it.