Files
hakorune/CURRENT_TASK.md
Selfhosting Dev 1f5ba5f829 💢 The truth about Rust + LLVM development hell
ChatGPT5 struggling for 34+ minutes with Rust lifetime/build errors...
This perfectly illustrates why we need Phase 22 (Nyash LLVM compiler)\!

Key insights:
- 'Rust is safe and beautiful' - Gemini (who never fought lifetime errors)
- Reality: 500-line error messages, 34min debug sessions, lifetime hell
- C would just work: void* compile(void* mir) { done; }
- Python would work: 100 lines with llvmlite
- ANY language with C ABI would work\!

The frustration is real:
- We're SO CLOSE to Nyash self-hosting paradise
- Once bootstrapped, EVERYTHING can be written in Nyash
- No more Rust complexity, no more 5-7min builds
- Just simple, beautiful Box-based code

Current status:
- PHI/SSA hardening in progress (ChatGPT5)
- 'phi incoming value missing' in Main.esc_json/1
- Sealed SSA approach being implemented

The dream is near: Everything is Box, even the compiler\! 🌟
2025-09-12 05:48:59 +09:00

218 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Current Task (2025-09-11) — Phase 15 LLVMonly
Summary
- LLVM is the authoritative path; VM/Cranelift/Interpreter are not MIR14ready.
- Keep fallbacks minimal; fix MIR annotations first.
- ExternCall(console/debug) autoselects ptr/handle by IR type.
- StringBox NewBox i8* fast path; print/log choose automatically.
- Implement multi-function lowering and Call lowering for MIR14.
Update — 2025-09-12 (LLVM flow + BB naming)
- codegen/mod.rs match arms cleanup:
- BinOp: unify to instructions::lower_binop(...)
- BoxCall: delegate solely to instructions::lower_boxcall(...); removed unreachable legacy code
- BasicBlock naming made functionscoped and unique: create_basic_blocks now prefixes with function label (e.g., Main_join_2_bb23)
- Terminator fallback: when a MIR block lacks a terminator, emit a conservative jump to the next block (or entry if last)
- Build: cargo build --features llvm passes
- AOT emit status: improved (bb name collision resolved), but verifier still flags a missing terminator in Main.esc_json/1 (e.g., Main_esc_json_1_bb88)
- Likely cause: flow lowering edge case; MIR dump is correct, LLVM lowering missed a terminator
- Plan below addresses this with hardened flow lowering and instrumentation
Hot Update — 2025-09-12 (quick)
- Flow: moved function verify to postlower; added terminator fallback only when MIR lacks one
- Compare: allow ptr↔int comparisons for all ops via ptr→i64 bridge
- Strings: substring now accepts i64(handle) receiver (i2p); len/lastIndexOf stable
- Arrays: method_id未注入でも get/set/push/length を NyRT 経由で処理
- BoxCall: println→env.console.log フォールバック、同モジュール関数呼び出し/名前指定 invoke_by_name 経路を追加
- PHI: 文字列/Box等を含む場合は i8* を選択する型推定に改善
- 現在のブロッカー: esc_json/1 で「phi incoming value missing」
- 対応: emit_jump/emit_branch の incoming 配線をログ付きで点検し、値未定義箇所byname/fastpath戻りを補完
Plan — PHI/SSA Hardening (Sealed SSA)
- Sealed SSA 入れ替え(安全に段階導入)
- Blockごとに `sealed: bool``incomplete_phis: Map<Var, Phi>` を保持
- 値取得APIを一本化: `value_at_end_of_block(var, bb)` で vmap を再帰解決仮PHI生成
- `seal(bb)` で pred 確定後に incomplete_phis を埋め、`fold_trivial_phi` で単純化
- 配線の方向を整理
- emit_jump/emit_branch では直接 incoming を配線しないto 側で必要時に解決)
- fast/slow 両レーンは同じ Var に書く(合流で拾えるように)
- 型の前処理を一箇所へ
- Bool は i1 固定(必要なら zext は PHI 外側)
- ptr/int 混在禁止。必要箇所で ptrtoint/inttoptr を生成し、PHI では等型を保証
- 計測と検証
- `seal(bb)` 時に incomplete_phis が残れば panic場所特定
- `[PHI] add incoming var=.. pred=.. ty=..` をデバッグ出力
- verify は関数降下完了後に 1 回
- フォールバックのゲート
- by-name invoke は環境変数で明示ONデフォルトOFFにする方針に切替イズ低減
Refactor Policy
- 慌てず小さな箱モジュールを積む。必要なら随時リファクタリングOK。
- 代替案(必要時のみ): llvmlite の薄層で最低限の命令面を実装し、dep_tree_min_string を先に通す。
Done (today)
- BoxCall legacy block removed in LLVM codegen; delegation only.
- BinOp concat safety: minimal fallback for i8*+i64/i64+i8* when both sides are annotated String/Box → from_i8_string + concat_hh; otherwise keep concat_ss/si/is.
- String fastpath: length/len lowered to nyash.string.len_h (handle), with ptr→handle bridge when needed.
- Map corefirst: NewBox(MapBox) routes via nyash.env.box.new("MapBox") → NyRT特例でコアMapを生成。LLVM BoxCall(Map.size/get/set/has) は NyRT の nyash.map.* を呼ぶ。
- Plugin強制スイッチ: NYASH_LLVM_FORCE_PLUGIN_MAP=1 で MapBox のプラグイン経路を明示切替(デフォルトはコア)。
- Docs: ARCHITECTURE/LOWERING_LLVM/EXTERNCALL/PLUGIN_ABI を追加・整備。
- Smokes: pluginret green, map smoke greencorefirst
- ExternCall microsplit 完了: `externcall.rs``externcall/` ディレクトリ配下に分割し、
`console.rs`console/debug`env.rs`future/local/boxに切り出し。
ディスパッチは `externcall/mod.rs` に集約挙動差分なし・0diff
- String FastPath 追加LLVM/NYRT: `substring(start,end)``lastIndexOf(needle)` を実装。
- Compare: String/StringBox 注釈のときは内容比較(`nyash.string.eq_hh`)にブリッジ。
- LLVM 多関数 Lower の骨格を実装: 全関数を事前宣言→順次Lower→`ny_main` ラッパで呼び出し正規化。
- Call Lowering 追加MIR14の `MirInstruction::Call`: callee 文字列定数を解決し、対応するLLVM関数を呼び出し引数束縛・戻り値格納
Refactor — LLVM codegen instructions modularized (done)
- Goal achieved: `instructions.rs` を段階分割し、責務ごとに再配置0diff
- New layout under `src/backend/llvm/compiler/codegen/instructions/`:
- Core: `blocks.rs`BB生成/PHI事前作成, `flow.rs`Return/Jump/Branch, `consts.rs`, `mem.rs`, `arith.rs`Compare
- BoxCall front: `boxcall.rs`(ディスパッチ本体)
- Strings/Arrays/Maps fastpaths: `strings.rs`, `arrays.rs`, `maps.rs`
- Fields: `boxcall/fields.rs`getField/setField
- Tagged invoke: `boxcall/invoke.rs`method_idありの固定長/可変長)
- Marshal: `boxcall/marshal.rs`ptr→i64, f64→box→i64, tag分類
- Arith ops: `arith_ops.rs`Unary/Binary、文字列連結の特例含む
- Extern: `externcall.rs`console/debug/env.local/env.box.*
- NewBox: `newbox.rs``codegen/mod.rs` から委譲に一本化)
- Wiring: `instructions/mod.rs``pub(super) use ...` で再エクスポート。可視性は `pub(in super::super)`/`pub(super)` を維持。
- Build: `cargo build --features llvm` グリーン、挙動差分なし。
Next (short, focused)
- Call Lowering の分離(完了): `instructions/call.rs` に分割し、`mod.rs` から委譲。
- 多関数 Lower 検証: selfhost minimaldep_tree_min_stringを LLVM で通す(必要なら型注釈の微調整)。
- Flow lowering hardening (in progress next):
- Ensure every lowered block has a terminator; use builder.get_insert_block().get_terminator() guard before fallback
- Instrument perblock lowering (bid, has terminator?, emitted kind) to isolate misses
- Keep fallback minimal and only when MIR.block.terminator is None and LLVM has no terminator
- MIR readable debug tools:
- Add --dump-mir-readable to print Nyashlike pseudo code per function/block
- Optional DOT output (followup)
- Debug hints in MIR (debug builds only):
- Add #[cfg(debug_assertions)] fields like MirInstruction::debug_hint and MirMetadata::block_sources
- Gate emission by env (NYASH_MIR_DEBUG=1)
- Map コア専用エントリ化env.box.new 特例整理と代表スモークの常時化CI
- types.rs の将来分割(任意):
- `types/convert.rs`i64<->ptr, f64→box, `types/classify.rs`, `types/map_types.rs`
- 機能拡張(任意・別タスク):
- String AOT fastpaths拡充substring/indexOf/replace/trim/toUpper/toLower
- MapBox 生成のNyRT専用エントリ化env.box.new特例の解消
- Map.get の戻り型注釈の厳密化
- 代表スモークの追加とCI常時チェック
Risks/Guards
- Avoid broad implicit conversions; keep concat fallback gated by annotations only.
- Ensure nyash.map.* との一致core Map; plugin経路は環境変数で明示切替。
- Keep LLVM smokes green continuously; do not gate on VM/JIT.
## 🎉 LLVMプラグイン戻り値表示問題修正進行中2025-09-10
### ✅ **完了した主要成果**
1. **プラグイン実装** ✅ - `nyash.plugin.invoke_*`関数はnyrtライブラリに正常実装済み
2. **プラグイン呼び出し** ✅ - 環境変数なしでメソッド呼び出し成功
3. **戻り値型推論修正** ✅ - MIR builder にプラグインメソッド型推論追加
4. **by-id統一完了** ✅ - by-name方式削除、method_id方式に完全統一
5. **環境変数削減達成** ✅ - `NYASH_LLVM_ALLOW_BY_NAME=1`削除完了
6. **シンプル実行実現** ✅ - `./target/release/nyash --backend llvm program.nyash`
7. **codex TLV修正マージ完了** ✅ - プラグイン戻り値TLVタグ2/6/7対応2000行修正
8. **console.log ハンドル対応** ✅ - 不正なi64→i8*変換を修正、ハンドル対応関数に変更
9. **型変換エラー解消** ✅ - bool(i1)→i64拡張処理追加でLLVM検証エラー修正
### 🔬 **現在の動作状況**2025-09-11 最新):
- **プラグイン実行** ✅ - CounterBox、FileBox正常実行副作用OK
- **型エラー解消** ✅ - LLVM関数検証エラー修正済み
- **コンパイル成功** ✅ - 環境変数なしでLLVMバックエンド動作
- **条件分岐動作** ✅ - `if f.exists("file")` → "TRUE"/"FALSE"表示OK
- **LLVMコード生成の分割** ✅ - `codegen/` 下にモジュール化types/instructions
- **BoxCall Lower 移譲** ✅ - 実行経路は `instructions::lower_boxcall` に一本化(旧実装は到達不能)
- **スモーク整理** ✅ - `tools/llvm_smoke.sh` を環境変数整理。プラグイン戻り値スモーク追加
### 🔍 **根本原因判明**
**Task先生の詳細技術調査により特定**
- **不正なハンドル→ポインタ変換**: `build_int_to_ptr(iv, i8p, "arg_i2p")` でハンドル値3を直接メモリアドレス0x3として扱う不正変換
- **修正完了**: console.log を `nyash.console.log_handle(i64) -> i64` に変更、ハンドルレジストリ活用
### 🔍 **残存課題(新)**
#### 1. **プラグイン戻り値表示問題** 🔶 **←現在調査中**
**症状(修正後も継続)**:
- `CounterBox.get()` → 数値戻り値がprint()で空白
- `FileBox.read(path)` → 文字列戻り値がprint()で空白
- `FileBox.exists(path)` → if条件では動作、変数格納で失敗
- `local x = 42; print(x)` → 正常(問題はプラグイン戻り値のみ)
**残る問題の推定**:
- print()以外のExternCall処理にも同様の問題がある可能性
- MIR変数代入処理での型情報不整合
- プラグイン戻り値のハンドル→実値変換が不完全
#### 2. **LLVM BinOp 文字列連結まわり(新規スモークで再現)** 🔶
現象:
- 追加スモーク `ny-plugin-ret-llvm-smoke` で LLVM AOT オブジェクト生成中に `binop type mismatch` が発生
- ケース: `print("S=" + t)``t``StringBox.concat("CD")` の戻り値)
暫定分析:
- `+` 連結の BinOp Lower は (ptr+ptr / ptr+int / int+ptr) を NyRT シム経由で処理する設計
- `t` のLowerが i64 handleのままになっている/もしくは型注釈不足で ptr へ昇格できていない可能性
- `instructions::lower_boxcall` 内の `concat` 特例f64 fast-pathは撤去済み。以降は tagged invoke → dst 型注釈に応じて i64→ptr へ変換する想定
対応方針:
1) MIR の `value_types` に BoxCall 戻り値StringBoxの型注釈が入っているか確認不足時は MIR 側で注入)
2) BinOp 連結経路は fallback として (ptr + 非ptr) / (非ptr + ptr) に対して handle想定の i64→ptr 昇格を再確認
3) 上記fixの後、スモーク `NYASH_LLVM_PLUGIN_RET_SMOKE=1` を通し、VM/LLVM 一致を確認
メモ:
- 現状でも BoxCall は新経路に完全委譲済み。旧実装は到達不能削除準備OK
### 📊 **修正済みファイル**
- **src/mir/builder.rs** - プラグインメソッド戻り値型推論追加
- **src/backend/llvm/compiler.rs** - by-name方式削除、method_id統一
- **src/backend/llvm/compiler/codegen/mod.rs** - 分割に伴う委譲Const/Compare/Return/Jump/Branch/Extern/NewBox/Load/Store/BoxCall
- **src/backend/llvm/compiler/codegen/types.rs** - 型変換/分類/型マップ(新)
- **src/backend/llvm/compiler/codegen/instructions.rs** - Lower群を実装
- **tools/llvm_smoke.sh** - LLVM18 prefix整理・プラグイン戻り値スモーク追加
- **apps/tests/ny-plugin-ret-llvm-smoke/main.nyash** - プラグイン戻り値スモーク(新)
- **CLAUDE.md** - 環境変数セクション更新、コマンド簡素化
- **README.md / README.ja.md** - 環境変数説明削除
- **tools/llvm_smoke.sh** - テストスクリプト環境変数削除
### 🎯 **次期深堀り調査対象**
1. **プラグインランタイム戻り値パス詳細調査** - `crates/nyrt/src/lib.rs`
2. **LLVM BoxCall戻り値処理詳細分析** - `src/backend/llvm/compiler/real.rs` 戻り値変換
3. **MIR変数代入メカニズム調査** - BoxCall→変数の代入処理
4. **print()関数とプラグイン値の相性調査** - 型認識処理
5. **BinOp 連結の保険見直し** - 片方が i64 (handle) の場合に ptr に昇格する安全弾性
6. **BoxCall 旧実装の物理削除** - スモークグリーン後に `mod.rs` の死コードを除去
### ✅ **リファクタリング完了2025-09-11**
**PR #136マージ済み** - LLVMコンパイラモジュール化
- `compiler.rs` → 4モジュールに分割mod.rs, real.rs, mock.rs, mock_impl.in.rs
- プラグインシグネチャ読み込みを `plugin_sigs.rs` に移動
- BoxタイプID読み込みを `box_types.rs` に移動
- PR #134の型情報処理を完全保持
## 🎯 Restart Notes — Ny Syntax Alignment (20250907)
### 目的
- SelfHosting 方針Nyのみで工具を回す前段に合わせて、Ny 構文とコーディング規約を明示化し、最小版ツールの完走性を優先。
### Ny 構文(実装時の基準)
- 1行1文セミコロン非使用。
- break / continue を使わない(関数早期 return、番兵条件、if 包みで置換)。
- else は直前の閉じ波括弧と同一行(`} else {`})。
- 文字列の `"``\` は確実にエスケープ。
- 反復は `loop(条件) { …; インクリメント }` を基本とし、必要に応じて「関数早期 return」型で早期脱出。
### 短期タスクSyntax 合意前提で最小ゴール)
1) include のみ依存木Nyのみ・配列/マップ未使用)を完走化
- `apps/selfhost/tools/dep_tree_min_string.nyash`
- FileBox/PathBox + 文字走査のみで JSON 構築(配列/マップに頼らない)
- `make dep-tree``tmp/deps.json` を出力
2) using/module 対応は次段(構文・優先順位をユーザーと再すり合わせ後)
- 優先: `module > 相対 > using-path`、曖昧=エラー、STRICT ゲート(要相談)
3) ブリッジ Stage 1 は保留
- `NYASH_DEPS_JSON=<path>` 読み込みログ出力のみを最小パッチで用意MIR/JIT/AOT は不変)