Phase 10.7 (NYASH_JIT_PHI_MIN=1): Minimal PHI support for single-diamond via block params; extend IRBuilder with block-param/jump-args APIs; implement in CraneliftBuilder; update LowerCore two-pass for PHI wiring.

This commit is contained in:
Moe Charm
2025-08-27 17:52:37 +09:00
parent 6bfb38949c
commit 633a073a30
13 changed files with 706 additions and 45 deletions

View File

@ -2,14 +2,15 @@
フェーズ10はJIT実用化へCore-1 Lowerの雛形を固めつつ、呼出/フォールバック導線を整えるよ。
## ⏱️ 今日のサマリ10_c実行経路の堅牢化GC/スケジューラ導線)
## ⏱️ 今日のサマリ10_c実行経路の堅牢化10_7分岐配線GC/スケジューラ導線)
- 目的: JIT実行を安全に通す足場を仕上げつつ、GC/スケジューラ導線を整備し回帰検出力を上げる。
- 10_c: panic→VMフォールバック`catch_unwind`/ JIT経路のroot区域化 / Core-1 i64 param minimal pass`emit_param_i64` + LowerCoreで供給
- 10_c: panic→VMフォールバック`catch_unwind`/ JIT経路のroot区域化 / Core-1 i64 param minimal pass`emit_param_i64` + LowerCoreで供給✅ 完了
- 10_4a/10_4b: GC導線 + Write-Barrier挿入ArraySet/RefSet/BoxCall、root APIenter/pin/leave
- 10_4c: CountingGcカウンタ出力roots/BoxRef内訳、depth2リーチャビリティ観測`NYASH_GC_TRACE=1/2/3`)✅ 完了
- 10_4d: STRICTバリア検証CountingGc前後比較で漏れ即検出✅ 完了(`NYASH_GC_BARRIER_STRICT=1`
- 10_6b: シングルスレ・スケジューラspawn/spawn_after/poll、Safepointで`poll()`連携、`NYASH_SCHED_POLL_BUDGET`対応 ✅ 完了
- ベンチ: CLIベンチへJIT比較追加ウォームアップあり、スクリプト版`examples/ny_bench.nyash`追加TimerBoxでops/sec
- 10_7: JIT分岐配線Cranelift— MIR Branch/Jump→CLIFブロック配線、条件b1保持、分岐b1/`i64!=0`両対応feature: `cranelift-jit`
- ベンチ: CLIベンチへJIT比較追加ウォームアップあり`branch_return`ケース追加、スクリプト版`examples/ny_bench.nyash`追加TimerBoxでops/sec
### 直近タスク(小さく早く)
1) 10_b: Lower/Core-1 最小化(進行中 → ほぼ完了)
@ -25,12 +26,17 @@
- JIT実行→`VMValue`返却、panic時VMフォールバック ✅(`engine.execute_handle``catch_unwind`
- Core-1最小: i64 param/return、Const(i64/bool→0/1)、BinOp/Compare/Return ✅
- HostCall最小Array/Map: len/get/set/push/sizeゲート`NYASH_JIT_HOSTCALL=1`
- Branch/Jumpは統計カウントまでCLIFブロック配線は後続フェーズで拡張
- Branch/JumpはCranelift配線導入済みfeature `cranelift-jit`。副作用命令は未lowerのためVMへフォールバック
3) 10_7: 分岐配線Cranelift— 進捗中
- LowerCore: BB整列・マッピング→builderの`prepare_blocks/switch/seal/br_if/jump`呼出 ✅
- CraneliftBuilder: ブロック配列管理、`brif/jump`実装、条件b1/`i64!=0`両対応 ✅
- 残: 最小PHI単純ダイアモンド導入`NYASH_JIT_PHI_MIN=1`ガード)/ 副作用命令の扱い方針当面VMへ
備考(制限と次の着手点)
- 返り値はi64VMValue::Integerに限定。f64はconst最小emit、boolはi64 0/1へ正規化分岐条件入力に対応
- 引数はi64のみ最小パス。複数引数はparamマッピングで通過、非i64は未対応 → 次対応
- Branch/JumpのCLIF配線は準備済み(ビルダー側は統計カウント。CLIFブロック配線は後続で実装。
- Branch/JumpのCLIF配線は導入済み(feature `cranelift-jit`。条件はb1で保持し、必要に応じて`i64!=0`で正規化
- 副作用命令print等はJIT未対応のためVMへ委譲安全性優先
- JIT/VM統合統計フォールバック率/時間の一括出力)未統合 → 次対応
### すぐ試せるコマンド
@ -45,6 +51,12 @@ NYASH_JIT_STATS=1 NYASH_JIT_DUMP=1 NYASH_JIT_EXEC=1 \
# 任意Craneliftを含めてビルド今は最小初期化のみ
cargo build --release -j32 --features cranelift-jit
# JIT分岐デモfeature有効時
NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 \
./target/release/nyash --backend vm examples/jit_branch_demo.nyash
NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 \
./target/release/nyash --backend vm examples/jit_loop_early_return.nyash
# スクリプトベンチTimerBox版
./target/release/nyash examples/ny_bench.nyash
./target/release/nyash --backend vm examples/ny_bench.nyash
@ -92,6 +104,11 @@ NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 ./target/release/nyash --backend vm examp
- STRICTモードのCI導入CountingGc前提/ goldenベンチ導入
- 10_6b:
- スケジューラ: poll予算の設定ファイル化、将来のscript API検討継続
- 10_7:
- 最小PHI単純ダイアモンドの導入`NYASH_JIT_PHI_MIN=1`ガード)
- IRBuilder APIの整理block param/分岐引数の正式化とCranelift実装の安定化
- 副作用命令のJIT扱い方針: 当面VMへ、将来はHostCall化
- CFG検証と`NYASH_JIT_DUMP=1`でのCFG可視化
- ベンチ:
- `examples/ny_bench.nyash`のケース追加(関数呼出/Map set-getとループ回数のenv化

View File

@ -0,0 +1,27 @@
# Phase 10.1a - 計画と設計
## 🎯 このフェーズの目的
PythonParserBoxの全体計画を理解し、実装の方向性を把握する。
## 📁 含まれるファイル
- **`pythonparser_integrated_plan_summary.txt`** - 統合実装計画(最重要)
- **`expert_feedback_gemini_codex.txt`** - Gemini先生とCodex先生の技術評価
- **`archive/`** - 初期検討資料
## ✅ 完了条件
- [ ] 統合計画を読んで理解
- [ ] エキスパートフィードバックを確認
- [ ] 5つの核心戦略を把握
- 関数単位フォールバック
- Python 3.11固定
- 意味論の正確な実装優先
- GIL管理の最小化
- テレメトリー重視
## 📝 重要ポイント
- **Differential Testing戦略** - 世界中のPythonコードがテストケースに
- **段階的実装** - 完璧を求めず動くものから
- **成功の測定基準** - カバレッジ率70%以上、性能向上2-10倍
## ⏭️ 次のフェーズ
→ Phase 10.1b (環境設定)

View File

@ -0,0 +1,55 @@
# Phase 10.1b - 環境設定とセットアップ
## 🎯 このフェーズの目的
PythonParserBox実装に必要な開発環境を整える。
## 📋 セットアップ手順
### 1. Python 3.11環境の固定
```bash
# pyenvを使用する場合
pyenv install 3.11.9
pyenv local 3.11.9
# または直接指定
python3.11 --version # 3.11.9であることを確認
```
### 2. Cargo.tomlへの依存関係追加
```toml
[dependencies]
pyo3 = { version = "0.22", features = ["auto-initialize"] }
pyo3-numpy = "0.22" # NumPy連携用Phase 3で使用
serde_json = "1.0" # JSON中間表現用
```
### 3. 環境変数の設定
```bash
# テレメトリー用
export NYASH_PYTHONPARSER_TELEMETRY=1 # 基本統計
export NYASH_PYTHONPARSER_TELEMETRY=2 # 詳細ログ
export NYASH_PYTHONPARSER_STRICT=1 # フォールバック時にパニックCI用
```
### 4. ディレクトリ構造の準備
```
src/boxes/python_parser_box/
├── mod.rs # メインモジュール
├── py_helper.rs # Python側ヘルパー
├── converter.rs # AST変換器
└── telemetry.rs # テレメトリー実装
```
## ✅ 完了条件
- [ ] Python 3.11.9がインストールされている
- [ ] Cargo.tomlに依存関係が追加されている
- [ ] 開発ディレクトリ構造が準備されている
- [ ] 環境変数の設定方法を理解している
## 🚨 注意事項
- **Python 3.11固定必須** - AST安定性のため
- **pyo3::prepare_freethreaded_python()** を一度だけ呼ぶ
- GIL管理に注意Phase 10.1cで詳細)
## ⏭️ 次のフェーズ
→ Phase 10.1c (パーサー統合実装)

View File

@ -0,0 +1,61 @@
# Phase 10.1c - パーサー統合実装
## 🎯 このフェーズの目的
pyo3を使ってCPythonパーサーをNyashに統合し、Python AST → JSON → Nyash ASTの変換パイプラインを構築する。
## 📁 実装ドキュメント
- **`python_parser_box_implementation_plan.txt`** - 技術的実装計画
- **`builtin_box_implementation_flow.txt`** - ビルトインBox実装フロー
## 🔧 実装タスク
### 1. PythonParserBoxの基本構造
```rust
pub struct PythonParserBox {
base: BoxBase,
py_helper: Arc<Mutex<PyHelper>>,
}
```
### 2. GIL管理の実装
```rust
// ✅ 良い例GILを最小限に
let json_ast = Python::with_gil(|py| {
py_helper.parse_to_json(py, code)
})?;
// GIL外でRust処理
let nyash_ast = py.allow_threads(|| {
convert_json_to_nyash(json_ast)
});
```
### 3. Python側ヘルパー実装
- `ast.parse()` → JSON変換
- 位置情報の保持lineno, col_offset
- Python 3.11固定チェック
### 4. 関数単位フォールバック判定
```rust
pub fn can_compile(&self, func_def: &PythonAst) -> CompileResult {
// サポートされているノードかチェック
// CompileResult::Compile or CompileResult::Fallback
}
```
## ✅ 完了条件
- [ ] PythonParserBoxがビルトインBoxとして登録されている
- [ ] `parse_to_json()` メソッドが動作する
- [ ] GIL管理が適切に実装されている
- [ ] テレメトリー基盤が組み込まれている
- [ ] 簡単なPythonコードでJSON ASTが取得できる
## 🧪 動作確認
```nyash
local py = new PythonParserBox()
local json_ast = py.parse_to_json("def hello(): return 'Hello'")
print(json_ast) // JSON ASTが表示される
```
## ⏭️ 次のフェーズ
→ Phase 10.1d (Core実装)

View File

@ -0,0 +1,72 @@
# Phase 10.1d - Core実装Phase 1機能
## 🎯 このフェーズの目的
Python AST → Nyash AST変換のPhase 1機能基本構文を実装する。
## 📁 実装ドキュメント
- **`python_implementation_roadmap.txt`** - Phase別実装ロードマップ
## 🔧 Phase 1必須要素Codex先生強調
### 意味論の必須実装
1. **LEGB + locals/freevars** - スコーピング規則
2. **デフォルト引数の評価タイミング** - 定義時に一度だけ
3. **イテレータベースのfor文** - `__iter__`/`__next__`プロトコル
4. **for/else + while/else** - Python独特のelse節
5. **Python真偽値判定** - `__bool__``__len__`
6. **短絡評価** - and/orの正確な挙動
### サポートする文Statement
- [x] def - 関数定義
- [x] if/elif/else - 条件分岐
- [x] for - ループelse節対応必須
- [x] while - ループelse節対応必須
- [x] break/continue - ループ制御
- [x] return - 戻り値
### サポートする式Expression
- [x] 算術演算子(+,-,*,/,//,%
- [x] 比較演算子(==,!=,<,>,<=,>=,is,is not
- [x] 論理演算子and,or,not- 短絡評価
- [x] 関数呼び出し
- [x] 変数参照/代入
- [x] リテラル(数値/文字列/bool
## 🧪 テストケース
```python
# Phase 1で動作すべきコード
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
# for/else のテスト
for i in range(10):
if i == 5:
break
else:
print("No break") # 実行されない
# デフォルト引数の罠
def append_to_list(item, lst=[]): # 定義時に評価!
lst.append(item)
return lst
```
## ✅ 完了条件
- [ ] 基本的な関数定義が変換できる
- [ ] 制御フローが正しく変換される
- [ ] 演算子が正しくマッピングされる
- [ ] Python意味論が保たれている
- [ ] 70%以上の関数がコンパイル可能
## 📊 テレメトリー確認
```bash
[PythonParser] Module: test.py (Python 3.11)
Functions: 10 total
Compiled: 7 (70%) ← 目標達成!
Fallback: 3 (30%)
```
## ⏭️ 次のフェーズ
→ Phase 10.1e (トランスパイラー)

View File

@ -0,0 +1,70 @@
# Phase 10.1e - Python → Nyashトランスパイラー
## 🎯 このフェーズの目的
Python ASTをNyashソースコードとして出力する機能を実装する。
## 📁 実装ドキュメント
- **`python_to_nyash_transpiler.txt`** - トランスパイラー設計
## 🔧 実装機能
### 1. AST → Nyashソース生成
```rust
impl PythonParserBox {
pub fn to_nyash_source(&self, python_code: &str) -> Result<String, String> {
// Python → JSON AST → Nyash AST → Nyashソース
}
}
```
### 2. 変換例
```python
# Python入力
def add(x, y):
return x + y
result = add(10, 5)
```
```nyash
# Nyash出力
function add(x, y) {
return x + y
}
local result
result = add(10, 5)
```
### 3. 出力フォーマッター
- インデント管理
- 括弧の追加Nyashは明示的
- コメント保持(可能な範囲で)
## 🛠️ コマンドラインツール
```bash
# 基本変換
nyash-transpile input.py -o output.nyash
# 変換統計付き
nyash-transpile --stats complex.py
# Output: Converted 15/17 functions (88%)
# 部分変換(サポート関数のみ)
nyash-transpile --partial script.py
```
## ✅ 完了条件
- [ ] `to_nyash_source()` メソッドが動作する
- [ ] 基本的なPythonコードが正しいNyashに変換される
- [ ] インデントが正しく管理される
- [ ] 変換統計が表示される
- [ ] ファイル出力ができる
## 🌟 期待される利用シーン
1. **学習ツール** - PythonユーザーがNyash構文を学ぶ
2. **段階的移行** - 既存Pythonコードの移行
3. **性能最適化** - ホットパスをNyashネイティブに
## ⏭️ 次のフェーズ
→ Phase 10.1f (テストとベンチマーク)

View File

@ -0,0 +1,92 @@
# Phase 10.1f - テストとベンチマーク
## 🎯 このフェーズの目的
Differential Testingでバグを発見し、性能向上を検証する。
## 🧪 Differential Testing戦略
### 1. テストフレームワーク
```rust
pub fn differential_test(code: &str) -> TestResult {
// CPythonで実行オラクル
let python_result = capture_python_execution(code)?;
// Nyashで実行
let nyash_result = execute_with_pythonparser(code)?;
// 結果比較
compare_results(python_result, nyash_result)
}
```
### 2. 比較項目
- **標準出力** - print文の結果
- **戻り値** - 関数の返す値
- **例外** - エラーメッセージ(正規化後)
- **副作用** - グローバル変数の変更等
### 3. テストコーパス
```
test_corpus/
├── basic/ # 基本構文テスト
├── stdlib/ # 標準ライブラリから抜粋
├── pypi_top100/ # 人気ライブラリから抜粋
└── edge_cases/ # エッジケース集
```
## 📊 ベンチマーク
### 1. 性能測定対象
```python
# 数値計算ベンチマーク
def mandelbrot(max_iter=100):
# フラクタル計算
pass
# ループベンチマーク
def sum_of_primes(n):
# 素数の和
pass
# 再帰ベンチマーク
def ackermann(m, n):
# アッカーマン関数
pass
```
### 2. 測定項目
- **実行時間** - CPython vs Nyash
- **メモリ使用量** - 最大/平均
- **コンパイル時間** - AST変換時間
- **フォールバック率** - 関数別統計
## 🐛 バグ発見と報告
### 発見されたバグの例
```
[BUG-001] for/else semantics mismatch
Python: else executed when no break
Nyash: else never executed
Fixed in: commit abc123
[BUG-002] Division operator difference
Python: 5/2 = 2.5 (float)
Nyash: 5/2 = 2 (integer)
Fixed in: commit def456
```
## ✅ 完了条件
- [ ] Differential Testingフレームワークが動作する
- [ ] 基本的なテストコーパスが準備されている
- [ ] 10個以上のバグを発見・修正
- [ ] ベンチマークで2倍以上の高速化を確認
- [ ] CI/CDパイプラインに統合されている
## 📈 成功の測定
- **カバレッジ率**: 70%以上の関数がコンパイル
- **性能向上**: 純Pythonループで2-10倍
- **バグ発見数**: Phase毎に10件以上
- **テスト成功率**: 95%以上
## ⏭️ 次のフェーズ
→ Phase 10.1g (ドキュメント作成)

View File

@ -0,0 +1,100 @@
# Phase 10.1g - ドキュメントとリリース準備
## 🎯 このフェーズの目的
PythonParserBoxの使い方を文書化し、コミュニティに公開する準備をする。
## 📚 作成するドキュメント
### 1. ユーザーガイド
- **Getting Started** - 最初の一歩
- **Python互換性ガイド** - サポートされる構文
- **トランスパイラー使用法** - Python→Nyash変換
- **トラブルシューティング** - よくある問題と解決法
### 2. API リファレンス
```nyash
// PythonParserBox API
box PythonParserBox {
// Python code → JSON AST
parse_to_json(code: String) -> String
// JSON AST → Nyash AST
json_to_nyash_ast(json: String) -> AstBox
// Python code → Nyash source
to_nyash_source(code: String) -> String
// 直接実行(関数単位フォールバック)
run(code: String) -> Box
// 変換統計
get_conversion_stats() -> MapBox
}
```
### 3. 移行ガイド
- **段階的移行戦略** - Pythonプロジェクトの移行手順
- **パフォーマンスチューニング** - ホットパスの最適化
- **ベストプラクティス** - 推奨される使い方
### 4. 内部設計ドキュメント
- **アーキテクチャ** - 全体設計
- **関数単位フォールバック** - 実装詳細
- **GIL管理** - pyo3との統合
- **テレメトリー** - 統計収集の仕組み
## 🎬 デモとチュートリアル
### 1. 動画チュートリアル
- 5分で分かるPythonParserBox
- Python→Nyash移行実演
- パフォーマンス比較デモ
### 2. サンプルプロジェクト
```
examples/
├── hello_python/ # 最小限の例
├── data_analysis/ # データ分析の移行例
├── web_api/ # WebAPIの移行例
└── benchmarks/ # ベンチマーク比較
```
## 📣 リリース準備
### 1. リリースノート作成
```markdown
# PythonParserBox v1.0 リリース!
## 🎉 新機能
- Python AST → Nyash AST変換
- 関数単位フォールバック
- Python→Nyashトランスパイラー
- Differential Testing
## 📊 パフォーマンス
- 純Pythonループ: 2-10倍高速化
- 数値計算: 5倍以上の改善
- メモリ効率: 30%削減
## 🐛 発見されたバグ
- Nyashパーサー: 15件修正
- セマンティクス: 8件修正
```
### 2. ブログ記事
- 「なぜPythonParserBoxを作ったのか」
- 「Differential Testingの威力」
- 「Everything is Boxの新たな展開」
## ✅ 完了条件
- [ ] ユーザーガイドが完成している
- [ ] APIリファレンスが完成している
- [ ] サンプルプロジェクトが動作する
- [ ] リリースノートが準備されている
- [ ] CI/CDでの自動テストが通る
## 🎯 Phase 10.1の完了!
これでPythonParserBoxの最初のリリースが完成
## ⏭️ 次の展開
→ Phase 10.2 (Phase 2機能の実装) または Phase 10.x (他言語対応)

View File

@ -1,52 +1,79 @@
# Phase 10.1 - PythonParserBox実装計画
# Phase 10.1 - PythonParserBox実装
このフォルダには、NyashとPythonの相互運用を実現するPythonParserBoxの実装計画が含まれています
見ただけで実装手順が分かる!順番通りに進めてください
## 📁 フォルダ構造
## 📂 サブフェーズ構成(順番に実行)
### メイン実装ドキュメント(最新版)
- **`pythonparser_integrated_plan_summary.txt`** - 統合実装計画サマリー(最重要)
- **`python_implementation_roadmap.txt`** - 実装ロードマップ(エキスパート統合版)
- **`python_parser_box_implementation_plan.txt`** - 技術的実装計画(統合版)
- **`builtin_box_implementation_flow.txt`** - ビルトインBox実装フロー統合版
- **`python_to_nyash_transpiler.txt`** - Python→Nyashトランスパイラー機能
### 📋 Phase 10.1a - 計画と設計
最初にここから!全体像を理解する。
- 統合実装計画を読む
- エキスパート評価を確認
- 5つの核心戦略を把握
### エキスパート評価
- **`expert_feedback_gemini_codex.txt`** - Gemini先生とCodex先生のフィードバック全文
### ⚙️ Phase 10.1b - 環境設定
開発環境を整える。
- Python 3.11.9をインストール
- Cargo.tomlに依存関係追加
- ディレクトリ構造準備
### アーカイブ(参考資料)
- **`archive/`** フォルダ
- `python_parser_box_design.txt` - 初期設計案
- `chatgpt5_original_idea.txt` - ChatGPT5の元アイデア
- `summary_2025_08_27.txt` - 当日の議論まとめ
### 🔧 Phase 10.1c - パーサー統合
CPythonパーサーをNyashに統合。
- PythonParserBox実装
- GIL管理の実装
- JSON中間表現への変換
## 🎯 Phase 10.1の目標
### 💻 Phase 10.1d - Core実装
基本的なPython構文の変換。
- Phase 1機能def/if/for/while
- 意味論の正確な実装
- 70%コンパイル率達成
1. **Pythonエコシステムの即座活用** - 既存Pythonライブラリの利用
2. **Differential Testing** - Nyashパーサーのバグ自動検証
3. **言語成熟度の向上** - 実用的なPythonコードでのストレステスト
### 🔄 Phase 10.1e - トランスパイラー
Python→Nyashソース変換。
- AST→Nyashソース生成
- フォーマッター実装
- コマンドラインツール
## 🔑 核心戦略(エキスパート推奨)
### 🧪 Phase 10.1f - テスト
Differential Testingでバグ発見。
- CPython vs Nyash比較
- ベンチマーク実行
- バグ修正とCI統合
1. **関数単位フォールバック** - ファイル全体でなく関数レベルで切り替え
2. **Python 3.11固定** - AST安定性の確保
3. **意味論の正確な実装** - 最適化より互換性優先
4. **GIL管理の最小化** - Python側でJSON生成、Rust側で処理
5. **テレメトリー重視** - 継続的な改善のための計測
### 📚 Phase 10.1g - ドキュメント
使い方を文書化してリリース。
- ユーザーガイド作成
- APIリファレンス
- サンプルプロジェクト
## 📋 実装フェーズ
## 🎯 各フェーズの目安時間
- **Phase 1**: Core Subset基本構文- 2週間
- **Phase 2**: Data Model特殊メソッド- 3週間
- **Phase 3**: Advanced Features高度な機能- 1ヶ月
- **Phase 4**: Modern Python最新機能- 将来
| フェーズ | 内容 | 目安時間 |
|---------|------|----------|
| 10.1a | 計画理解 | 2-3時間 |
| 10.1b | 環境設定 | 1-2時間 |
| 10.1c | パーサー統合 | 3-5日 |
| 10.1d | Core実装 | 1-2週間 |
| 10.1e | トランスパイラー | 3-5日 |
| 10.1f | テスト | 1週間 |
| 10.1g | ドキュメント | 3-5日 |
## 🚀 期待される成果
**合計**: 約1ヶ月
- 純Pythonループの2-10倍高速化
- Nyashパーサーのバグ発見と改善
- PythonからNyashへの段階的移行パス
- Python→Nyashスクリプト変換機能
## 🌟 最終目標
- **70%以上**の関数がコンパイル可能
- **2-10倍**の性能向上
- **10件以上**のNyashバグ発見
- **実用的な**Python→Nyash移行ツール
## 💡 Tips
- 各フェーズのREADME.mdを必ず読む
- 完了条件をチェックしながら進める
- テレメトリーで進捗を確認
- 困ったらarchive/の資料も参照
---
作成日: 2025-08-27
**さあ、Phase 10.1a から始めましょう!**

View File

@ -0,0 +1,17 @@
// JIT loop early-return demo (no PHI needed)
// Enable: NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1
static box Main {
main() {
local i
i = 0
loop(i < 10) {
if (i == 3) {
return 99
}
i = i + 1
}
return -1
}
}

View File

@ -36,6 +36,17 @@ pub trait IRBuilder {
fn br_if_top_is_true(&mut self, _then_index: usize, _else_index: usize) { }
/// Optional: unconditional jump to target block index
fn jump_to(&mut self, _target_index: usize) { }
/// Optional: ensure target block has one i64 block param (for minimal PHI)
fn ensure_block_param_i64(&mut self, _index: usize) { }
/// Optional: push current block's first param (i64) onto the value stack
fn push_block_param_i64(&mut self) { }
/// Optional: conditional branch with explicit arg counts for then/else; pops args from stack
fn br_if_with_args(&mut self, _then_index: usize, _else_index: usize, _then_n: usize, _else_n: usize) {
// fallback to no-arg br_if
self.br_if_top_is_true(_then_index, _else_index);
}
/// Optional: jump with explicit arg count; pops args from stack
fn jump_with_args(&mut self, _target_index: usize, _n: usize) { self.jump_to(_target_index); }
}
pub struct NoopBuilder {
@ -76,6 +87,7 @@ pub struct CraneliftBuilder {
// Phase 10.7: basic block wiring state
blocks: Vec<cranelift_codegen::ir::Block>,
current_block_index: Option<usize>,
block_param_counts: std::collections::HashMap<usize, usize>,
// Finalized function pointer (if any)
compiled_closure: Option<std::sync::Arc<dyn Fn(&[crate::backend::vm::VMValue]) -> crate::backend::vm::VMValue + Send + Sync>>,
// Desired simple ABI (Phase 10_c minimal): i64 params count and i64 return
@ -427,6 +439,74 @@ impl IRBuilder for CraneliftBuilder {
self.stats.3 += 1;
fb.finalize();
}
fn ensure_block_param_i64(&mut self, index: usize) {
use cranelift_codegen::ir::types;
use cranelift_frontend::FunctionBuilder;
if index >= self.blocks.len() { return; }
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
let count = self.block_param_counts.get(&index).copied().unwrap_or(0);
if count == 0 {
let b = self.blocks[index];
let _v = fb.append_block_param(b, types::I64);
self.block_param_counts.insert(index, 1);
}
fb.finalize();
}
fn push_block_param_i64(&mut self) {
use cranelift_frontend::FunctionBuilder;
use cranelift_codegen::ir::types;
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
// Determine current block
let b = if let Some(idx) = self.current_block_index { self.blocks[idx] } else if let Some(b) = self.entry_block { b } else { fb.create_block() };
// Fetch first param if exists
let params = fb.func.dfg.block_params(b).to_vec();
if let Some(v) = params.get(0).copied() { self.value_stack.push(v); }
else {
// defensive: push 0
let zero = fb.ins().iconst(types::I64, 0);
self.value_stack.push(zero);
}
fb.finalize();
}
fn br_if_with_args(&mut self, then_index: usize, else_index: usize, then_n: usize, else_n: usize) {
use cranelift_codegen::ir::{types, condcodes::IntCC};
use cranelift_frontend::FunctionBuilder;
if then_index >= self.blocks.len() || else_index >= self.blocks.len() { return; }
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); }
else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
// Condition
let cond_b1 = if let Some(v) = self.value_stack.pop() {
let ty = fb.func.dfg.value_type(v);
if ty == types::I64 { fb.ins().icmp_imm(IntCC::NotEqual, v, 0) } else { v }
} else {
let zero = fb.ins().iconst(types::I64, 0);
fb.ins().icmp_imm(IntCC::NotEqual, zero, 0)
};
// Pop else args then then args (so stack order can be value-friendly)
let mut else_args: Vec<cranelift_codegen::ir::Value> = Vec::new();
for _ in 0..else_n { if let Some(v) = self.value_stack.pop() { else_args.push(v); } }
else_args.reverse();
let mut then_args: Vec<cranelift_codegen::ir::Value> = Vec::new();
for _ in 0..then_n { if let Some(v) = self.value_stack.pop() { then_args.push(v); } }
then_args.reverse();
fb.ins().brif(cond_b1, self.blocks[then_index], &then_args, self.blocks[else_index], &else_args);
self.stats.3 += 1;
fb.finalize();
}
fn jump_with_args(&mut self, target_index: usize, n: usize) {
use cranelift_frontend::FunctionBuilder;
if target_index >= self.blocks.len() { return; }
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); }
else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
let mut args: Vec<cranelift_codegen::ir::Value> = Vec::new();
for _ in 0..n { if let Some(v) = self.value_stack.pop() { args.push(v); } }
args.reverse();
fb.ins().jump(self.blocks[target_index], &args);
self.stats.3 += 1;
fb.finalize();
}
}
#[cfg(feature = "cranelift-jit")]
@ -474,6 +554,7 @@ impl CraneliftBuilder {
entry_block: None,
blocks: Vec::new(),
current_block_index: None,
block_param_counts: std::collections::HashMap::new(),
compiled_closure: None,
desired_argc: 0,
desired_has_ret: true,

View File

@ -24,10 +24,27 @@ impl LowerCore {
for (i, v) in func.params.iter().copied().enumerate() {
self.param_index.insert(v, i);
}
// Prepare block mapping (Phase 10.7 stub): deterministic ordering by sorted keys
// Prepare block mapping (Phase 10.7): deterministic ordering by sorted keys
let mut bb_ids: Vec<_> = func.blocks.keys().copied().collect();
bb_ids.sort_by_key(|b| b.0);
builder.prepare_blocks(bb_ids.len());
// Optional: collect single-PHI targets for minimal PHI path
let enable_phi_min = std::env::var("NYASH_JIT_PHI_MIN").ok().as_deref() == Some("1");
let mut phi_targets: std::collections::HashMap<crate::mir::BasicBlockId, std::collections::HashMap<crate::mir::BasicBlockId, crate::mir::ValueId>> = std::collections::HashMap::new();
if enable_phi_min {
for (bb_id, bb) in func.blocks.iter() {
// gather Phi instructions in this block
let mut phis: Vec<&crate::mir::MirInstruction> = Vec::new();
for ins in bb.instructions.iter() { if let crate::mir::MirInstruction::Phi { .. } = ins { phis.push(ins); } }
if phis.len() == 1 {
if let crate::mir::MirInstruction::Phi { inputs, .. } = phis[0] {
let mut map: std::collections::HashMap<crate::mir::BasicBlockId, crate::mir::ValueId> = std::collections::HashMap::new();
for (pred, val) in inputs.iter() { map.insert(*pred, *val); }
phi_targets.insert(*bb_id, map);
}
}
}
}
builder.prepare_signature_i64(func.params.len(), true);
builder.begin_function(&func.signature.name);
// Iterate blocks in the sorted order to keep indices stable
@ -48,13 +65,34 @@ impl LowerCore {
// Map BasicBlockId -> index
let then_index = bb_ids.iter().position(|x| x == then_bb).unwrap_or(0);
let else_index = bb_ids.iter().position(|x| x == else_bb).unwrap_or(0);
if enable_phi_min {
// For minimal PHI, pass one i64 arg if successor defines a single PHI with this block as pred
let mut then_n = 0usize;
let mut else_n = 0usize;
if let Some(pred_map) = phi_targets.get(then_bb) {
if let Some(v) = pred_map.get(bb_id) { self.push_value_if_known_or_param(builder, v); then_n = 1; builder.ensure_block_param_i64(then_index); }
}
if let Some(pred_map) = phi_targets.get(else_bb) {
if let Some(v) = pred_map.get(bb_id) { self.push_value_if_known_or_param(builder, v); else_n = 1; builder.ensure_block_param_i64(else_index); }
}
builder.br_if_with_args(then_index, else_index, then_n, else_n);
} else {
builder.br_if_top_is_true(then_index, else_index);
}
builder.seal_block(then_index);
builder.seal_block(else_index);
}
crate::mir::MirInstruction::Jump { target } => {
let target_index = bb_ids.iter().position(|x| x == target).unwrap_or(0);
if enable_phi_min {
let mut n = 0usize;
if let Some(pred_map) = phi_targets.get(target) {
if let Some(v) = pred_map.get(bb_id) { self.push_value_if_known_or_param(builder, v); n = 1; builder.ensure_block_param_i64(target_index); }
}
builder.jump_with_args(target_index, n);
} else {
builder.jump_to(target_index);
}
builder.seal_block(target_index);
}
_ => {
@ -168,6 +206,10 @@ impl LowerCore {
if let Some(v) = value { self.push_value_if_known_or_param(b, v); }
b.emit_return()
}
I::Phi { .. } => {
// Minimal PHI: load current block param as value (i64)
b.push_block_param_i64();
}
I::ArrayGet { array, index, .. } => {
if std::env::var("NYASH_JIT_HOSTCALL").ok().as_deref() == Some("1") {
// Push args: array param index (or -1), index (known or 0)