feat(joinir): L-5.3 Phase 1 - progress carrier guard for generic_case_a
## 実装内容 1. has_safe_progress() helper 追加 (loop_to_join.rs:186-195) - Phase 1: scope.progress_carrier.is_some() をチェック (保守的) - Phase 2 (future): MirQuery で Add 命令チェック予定 2. is_supported_case_a_loop_view() に progress guard 追加 (256-266) - 無限ループの可能性があるループを事前にフォールバック - デバッグログで reject 理由を出力 ## テスト結果 ✅ 25 passed; 0 failed - JoinIR 関連テスト全通過 ✅ skip_ws / trim / append_defs / Stage‑1 UsingResolver 全ケース PASS ✅ 既存テストへの影響なし ## 技術メモ - 保守的アプローチ: progress_carrier.is_some() のみチェック - LoopScopeShape で progress_carrier を carriers の先頭として設定済み - ignored テスト失敗は MIR 自体の PHI バグで、本変更とは無関係 (git stash で確認済み) 関連: Phase 29 L-5.3 (TASKS.md), CURRENT_TASK.md 1-00v
This commit is contained in:
135
CURRENT_TASK.md
135
CURRENT_TASK.md
@ -40,6 +40,104 @@
|
|||||||
|
|
||||||
## 1. 最近完了した重要タスク
|
## 1. 最近完了した重要タスク
|
||||||
|
|
||||||
|
### 1-00v. Phase 29 L-5.3 — JoinIR generic_case_a との統合 (Phase 1)(**完了** 2025-11-26)
|
||||||
|
|
||||||
|
**目的**
|
||||||
|
- generic_case_a lowering に progress carrier チェックを追加
|
||||||
|
- 無限ループの可能性があるループ(progress carrier なし)を事前にフォールバック
|
||||||
|
- 保守的アプローチで minimal 4 ケースの安定性確保
|
||||||
|
|
||||||
|
**実装内容**
|
||||||
|
1. `src/mir/join_ir/lowering/loop_to_join.rs` に `has_safe_progress()` helper 追加(Phase 1 実装)
|
||||||
|
- `scope.progress_carrier.is_some()` で保守的チェック
|
||||||
|
- Phase 2 で MirQuery による Add 命令チェック予定
|
||||||
|
2. `is_supported_case_a_loop_view()` の末尾に progress guard 追加(4 番目のチェック)
|
||||||
|
- progress carrier なしループは reject してフォールバック
|
||||||
|
- デバッグログで reject 理由を出力
|
||||||
|
|
||||||
|
**テスト結果**
|
||||||
|
- ✅ **25 passed; 0 failed** — JoinIR 関連テスト全通過
|
||||||
|
- ✅ skip_ws / trim / append_defs / Stage‑1 UsingResolver の全ケース PASS
|
||||||
|
- ✅ 既存テストへの影響なし(progress carrier が設定されているループは全て通過)
|
||||||
|
|
||||||
|
**技術メモ**
|
||||||
|
- Phase 1 は `progress_carrier.is_some()` だけチェック(保守的)
|
||||||
|
- LoopScopeShape で progress_carrier を carriers の先頭(典型的には 'i')として設定済み
|
||||||
|
- ignored テスト(joinir_vm_bridge_skip_ws Route A)の失敗は MIR 自体の PHI バグで、本変更とは無関係(git stash で確認済み)
|
||||||
|
|
||||||
|
**次のステップ**
|
||||||
|
- Phase 2: MirQuery で header→latch 間に Add 命令があるかの詳細チェック追加
|
||||||
|
- verify.rs の `verify_progress_for_skip_ws()` ロジックを MIR レベルに適用
|
||||||
|
|
||||||
|
**関連ファイル**
|
||||||
|
- `src/mir/join_ir/lowering/loop_to_join.rs` (has_safe_progress + progress guard)
|
||||||
|
- `docs/private/roadmap2/phases/phase-29-longterm-joinir-full/TASKS.md` (L-5.3 完了記録)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1-00u. Phase 32 L-4.3a — llvmlite ハーネスでの JoinIR 実験(**完了** 2025-11-26)
|
||||||
|
|
||||||
|
**目的**
|
||||||
|
- LLVM 経路で JoinIR が PHI 問題を解決できることを実行レベルで実証
|
||||||
|
- Route A (MIR→LLVM) vs Route B (MIR→JoinIR→MIR'→LLVM) の比較検証
|
||||||
|
|
||||||
|
**実装内容**
|
||||||
|
1. `src/config/env.rs` に `joinir_llvm_experiment_enabled()` 追加
|
||||||
|
- `NYASH_JOINIR_LLVM_EXPERIMENT=1` で有効化
|
||||||
|
2. `src/runner/modes/llvm.rs` に JoinIR フック追加
|
||||||
|
- `inject_method_ids` の直後で JoinIR 変換を試行
|
||||||
|
- `Main.skip/1` を JoinIR 経由で変換し、元のモジュールとマージ
|
||||||
|
- 戦略: 元の `Main.skip/1`(PHI問題あり)を削除 → `join_func_0` を `Main.skip/1` にリネーム
|
||||||
|
|
||||||
|
**テスト結果**
|
||||||
|
- **Route A** (MIR→LLVM): PHI error ❌
|
||||||
|
```
|
||||||
|
PHINode should have one entry for each predecessor of its parent basic block!
|
||||||
|
%phi_11 = phi i64 [ %.1, %bb2 ], [ %.1, %bb5 ]
|
||||||
|
```
|
||||||
|
- **Route B** (MIR→JoinIR→MIR'→LLVM): **成功 ✅**
|
||||||
|
```
|
||||||
|
[joinir/llvm] ✅ Merged module (6 functions)
|
||||||
|
✅ LLVM (harness) execution completed (exit=0)
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用方法**
|
||||||
|
```bash
|
||||||
|
env NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \
|
||||||
|
NYASH_DISABLE_PLUGINS=1 NYASH_LLVM_USE_HARNESS=1 \
|
||||||
|
NYASH_JOINIR_EXPERIMENT=1 NYASH_JOINIR_LLVM_EXPERIMENT=1 \
|
||||||
|
./target/release/hakorune --backend llvm apps/tests/minimal_ssa_skip_ws.hako
|
||||||
|
```
|
||||||
|
|
||||||
|
**成果**: JoinIR が LLVM 経路でも PHI 問題を設計的に解決できることを実証
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1-00t. Phase 32 L-3.2 — Medium 優先度 PHI 箱の削除検討(**完了** 2025-11-26)
|
||||||
|
|
||||||
|
**目的**
|
||||||
|
- Medium 優先度の PHI 箱(if_phi.rs / if_body_local_merge.rs / phi_invariants.rs / conservative.rs)の削除可能性を調査
|
||||||
|
- 各箱の call site を A/B/C に分類(A: テスト専用、B: JoinIR 候補、C: 本線必須)
|
||||||
|
|
||||||
|
**調査結果**
|
||||||
|
1. **if_phi.rs**: 9箇所で使用(すべてカテゴリ C)
|
||||||
|
- lifecycle.rs, if_form.rs, phi.rs, conservative.rs, loop_builder.rs で MIR Builder の If/Else PHI 生成に必須
|
||||||
|
2. **if_body_local_merge.rs**: phi_builder_box.rs で使用(PhiBuilderBox に依存)
|
||||||
|
3. **phi_invariants.rs**: phi_builder_box.rs で検証用として使用(PhiBuilderBox に依存)
|
||||||
|
4. **conservative.rs**: phi_merge.rs, phi.rs で MIR Builder の PHI マージに必須(カテゴリ C)
|
||||||
|
|
||||||
|
**結論: Phase 32 時点では削除不可**
|
||||||
|
- すべての箱が MIR Builder の If/Else PHI 生成で必須(カテゴリ C)
|
||||||
|
- if_body_local_merge.rs と phi_invariants.rs は PhiBuilderBox(High 優先度)に依存
|
||||||
|
- JoinIR は **Loop 専門**で、If PHI はカバーしていない
|
||||||
|
- 削除は **Phase 33+ で If JoinIR 対応後**に再検討
|
||||||
|
|
||||||
|
**ドキュメント更新**
|
||||||
|
- `PHI_BOX_INVENTORY.md` に L-3.2 詳細分析を追記
|
||||||
|
- 各箱の call site 分類テーブルと削除不可理由を明文化
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### 1-00v. Phase 31 — LoopToJoinLowerer 統一箱(**完了** 2025-11-26)
|
### 1-00v. Phase 31 — LoopToJoinLowerer 統一箱(**完了** 2025-11-26)
|
||||||
|
|
||||||
**目的**
|
**目的**
|
||||||
@ -202,6 +300,20 @@ LoopScopeShape → CaseAContext::from_scope() → lower_case_a_X_core() → Join
|
|||||||
- `joinir_runner_standalone_skip_ws` / `joinir_runner_standalone_trim` / `joinir_vm_bridge_trim_*` / JSON v0 スナップショット系テストは全て PASS。
|
- `joinir_runner_standalone_skip_ws` / `joinir_runner_standalone_trim` / `joinir_vm_bridge_trim_*` / JSON v0 スナップショット系テストは全て PASS。
|
||||||
- Stage‑1 / Stage‑B については、`NYASH_JOINIR_LOWER_GENERIC` 有効時も lowering 自体は通ることを確認(意味論は簡略版のままなので VM 実行はまだ有効化しない)。
|
- Stage‑1 / Stage‑B については、`NYASH_JOINIR_LOWER_GENERIC` 有効時も lowering 自体は通ることを確認(意味論は簡略版のままなので VM 実行はまだ有効化しない)。
|
||||||
|
|
||||||
|
5. **ExitGroup ベースの Case-A 判定 refinement(L-1.4 完了 2025-11-26)**
|
||||||
|
- `src/mir/control_form.rs` に `ExitGroup { target, edges, has_break }` と `ExitAnalysis { loop_exit_groups, nonlocal_exits }` を追加し、ExitEdge の生配列から「出口ブロック単位のグループ」と「非局所 exit(Return/Throw 等)」を切り出すビューを実装。
|
||||||
|
- `analyze_exits(exits: &[ExitEdge]) -> ExitAnalysis` で:
|
||||||
|
- `loop_exit_groups`: ループ本体からループ外の同じ after-block へ出る出口グループ(ExitKind::ConditionFalse / Break のみ)
|
||||||
|
- `nonlocal_exits`: ExitKind::Return / Throw / outer break など非局所 exit
|
||||||
|
に分類。
|
||||||
|
- `loop_to_join.rs` の `is_supported_case_a_loop_view` を ExitAnalysis ベースに差し替え:
|
||||||
|
- 旧ロジック: `control.exits.len() == 1` で単一 ExitEdge を要求していたため、複雑条件 break(短絡 && でブロックが分かれる)を Case-A から外していた。
|
||||||
|
- 新ロジック: `exit_analysis.loop_exit_groups.len() == 1`(出口ブロック集合が 1 種類)かつ `exit_analysis.nonlocal_exits.is_empty()`(非局所 exit なし)であれば Case-A とみなすように変更。
|
||||||
|
- 効果:
|
||||||
|
- `if c != ' ' && c != '\t' && c != '\n' { break }` のような複雑条件 break を含むループでも、出口ブロックが 1 種類であれば Case-A として LoopToJoinLowerer/JoinIR lowering の対象にできるようになった。
|
||||||
|
- Stage‑1 JoinIR VM bridge テスト 4 件(`joinir_vm_bridge_stage1_*`)は全て PASS を維持。
|
||||||
|
- skip_ws 実物については、JoinIR 経由の PHI 形状は引き続き正しく表現できているが、VM 実行側では `StepBudgetExceeded`(既知の別問題)が残っているため、挙動は L-4/L-5(VM / progress carrier まわり)のフェーズで継続調査する。
|
||||||
|
|
||||||
**成果物(L-2.1: Stage‑1 UsingResolver 本線ループ)**
|
**成果物(L-2.1: Stage‑1 UsingResolver 本線ループ)**
|
||||||
1. **本線ループを LoopToJoinLowerer 対象に昇格**
|
1. **本線ループを LoopToJoinLowerer 対象に昇格**
|
||||||
- 対象: `Stage1UsingResolverBox.resolve_for_source/5` 内の entries ループ(`lang/src/compiler/entry/using_resolver_box.hako:46-91`)。
|
- 対象: `Stage1UsingResolverBox.resolve_for_source/5` 内の entries ループ(`lang/src/compiler/entry/using_resolver_box.hako:46-91`)。
|
||||||
@ -284,7 +396,28 @@ LoopScopeShape → CaseAContext::from_scope() → lower_case_a_X_core() → Join
|
|||||||
- 最小ケース `minimal_ssa_skip_ws.hako` で `Main.skip(" abc")` を実行
|
- 最小ケース `minimal_ssa_skip_ws.hako` で `Main.skip(" abc")` を実行
|
||||||
- Route A(VM 直接): 結果 `0` ❌(PHI バグで値消失)
|
- Route A(VM 直接): 結果 `0` ❌(PHI バグで値消失)
|
||||||
- Route B(JoinIR): 結果 `Int(3)` ✅(正解)
|
- Route B(JoinIR): 結果 `Int(3)` ✅(正解)
|
||||||
- L-3 / L-4: これから(PHI レガシー削除と「JoinIR→VM/LLVM 前提」ランナー構造への仕上げ)。
|
- L-3.1 Step-1: **完了(2025-11-26)** — PHI レガシー箱の call site 分析
|
||||||
|
- PHI_BOX_INVENTORY.md を Phase 32 向けに更新(削除優先度 High/Medium/Low 分類)
|
||||||
|
- PhiBuilderBox / PhiInputCollector / LoopSnapshotMergeBox の call site を A/B/C 分類
|
||||||
|
- 結果: カテゴリ A(テスト専用)はコメント参照 1 箇所のみ
|
||||||
|
- L-3.1 Step-2: **完了(2025-11-26)** — PHI 経路削除可能性分析
|
||||||
|
- loopform_builder.rs: PhiInputCollector × 3, LoopSnapshotMergeBox × 1 → 非 JoinIR 経路で必須(削除不可)
|
||||||
|
- json_v0_bridge/loop_.rs: PhiInputCollector × 1 → selfhost 経路で必須(削除不可)
|
||||||
|
- **結論**: JoinIR は既に PHI 箱をバイパス。削除は L-4(JoinIR 本線化)完了後
|
||||||
|
- L-3.2 / L-3.3: これから(JoinIR 本線化後に PHI 箱削除)。
|
||||||
|
- L-4.1/L-4.2: **完了(2025-11-26)** — VM Bridge テーブル化 & 本線明示
|
||||||
|
- `join_ir_vm_bridge_dispatch.rs` に Descriptor テーブル(`JOINIR_TARGETS`)を導入し、関数名→役割のマッピングを一元管理。
|
||||||
|
- `JoinIrBridgeKind` 列挙型: **Exec**(JoinIR→VM 実行まで対応)と **LowerOnly**(lowering 検証のみ、実行は VM Route A)を明確に区別。
|
||||||
|
- 対象関数ごとの状態:
|
||||||
|
| 関数 | Kind | デフォルト有効 | 状態 |
|
||||||
|
|-----|------|---------------|------|
|
||||||
|
| `Main.skip/1` | Exec | ❌ | PHI canary のため本線化しない(env 必須) |
|
||||||
|
| `FuncScannerBox.trim/1` | Exec | ✅ | **唯一の本線昇格候補**(A/B 実証済み) |
|
||||||
|
| `Stage1UsingResolverBox.resolve_for_source/5` | LowerOnly | ❌ | 構造検証のみ |
|
||||||
|
| `StageBBodyExtractorBox.build_body_src/2` | LowerOnly | ❌ | 構造検証のみ |
|
||||||
|
| `StageBFuncScannerBox.scan_all_boxes/1` | LowerOnly | ❌ | 構造検証のみ |
|
||||||
|
- **結論**: 現状は **trim だけが「JoinIR 実行まで含めて安全」として昇格候補**。skip は PHI canary として残し、Stage-1/Stage-B は ArrayBox/MapBox 引数の JoinValue 対応が揃うまで LowerOnly。
|
||||||
|
- L-4.3: これから(LLVM ライン JoinIR 実験: まず llvmlite ハーネスで JoinIR→MIR'→LLVM の最小ケース 1 本を通し、その後 llvmc 側にミラーする計画。いずれも dev トグル前提の実験扱い)。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Submodule docs/private updated: 93927b869a...79cd258b45
@ -15,7 +15,7 @@
|
|||||||
//! let join_module = lowerer.lower(func, &loop_form, &query)?;
|
//! let join_module = lowerer.lower(func, &loop_form, &query)?;
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use crate::mir::control_form::{LoopControlShape, LoopId, LoopRegion};
|
use crate::mir::control_form::{analyze_exits, ExitEdge, LoopControlShape, LoopId, LoopRegion};
|
||||||
use crate::mir::join_ir::lowering::generic_case_a;
|
use crate::mir::join_ir::lowering::generic_case_a;
|
||||||
use crate::mir::join_ir::lowering::loop_form_intake::intake_loop_form;
|
use crate::mir::join_ir::lowering::loop_form_intake::intake_loop_form;
|
||||||
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
||||||
@ -123,8 +123,8 @@ impl LoopToJoinLowerer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase 32 L-1.1: View ベースの Case-A サポートチェック(構造判定強化)
|
// Phase 32 L-1.4: ExitAnalysis ベースの Case-A サポートチェック
|
||||||
if !self.is_supported_case_a_loop_view(func, ®ion, &control, &scope) {
|
if !self.is_supported_case_a_loop_view(func, ®ion, &control, &exit_edges, &scope) {
|
||||||
if self.debug {
|
if self.debug {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[LoopToJoinLowerer] rejected by view-based check: {:?}",
|
"[LoopToJoinLowerer] rejected by view-based check: {:?}",
|
||||||
@ -158,22 +158,61 @@ impl LoopToJoinLowerer {
|
|||||||
self.lower_with_scope(scope, func_name)
|
self.lower_with_scope(scope, func_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Phase 29 L-5.3: Progress carrier の安全性をチェック
|
||||||
|
///
|
||||||
|
/// 無限ループの可能性があるループ(progress carrier が無い、または更新されない)
|
||||||
|
/// を事前に弾く。
|
||||||
|
///
|
||||||
|
/// # Phase 1 実装(保守的)
|
||||||
|
///
|
||||||
|
/// - `scope.progress_carrier.is_some()` をチェック
|
||||||
|
/// - progress_carrier が設定されていればループは進捗すると仮定
|
||||||
|
///
|
||||||
|
/// # Phase 2 (future)
|
||||||
|
///
|
||||||
|
/// - MirQuery で header→latch 間に Add 命令があるかチェック
|
||||||
|
/// - skip_ws verifier のロジックを MIR レベルで簡略化して適用
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - `scope`: LoopScopeShape(progress_carrier 情報を持つ)
|
||||||
|
/// - `func`: MIR 関数(将来の MirQuery 用)
|
||||||
|
/// - `region`: LoopRegion(将来の header→latch チェック用)
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// - `true`: Progress carrier あり(safe)
|
||||||
|
/// - `false`: Progress carrier なし(unsafe、fallback すべき)
|
||||||
|
fn has_safe_progress(
|
||||||
|
scope: &LoopScopeShape,
|
||||||
|
_func: &MirFunction, // Phase 2 で使用予定
|
||||||
|
_region: &LoopRegion, // Phase 2 で使用予定
|
||||||
|
) -> bool {
|
||||||
|
// Phase 1: 保守的チェック
|
||||||
|
// progress_carrier が設定されていれば、ループは進捗すると仮定
|
||||||
|
// (典型的には 'i' のような loop index)
|
||||||
|
scope.progress_carrier.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
/// Case-A ループとしてサポートされているかチェック(View ベース版)
|
/// Case-A ループとしてサポートされているかチェック(View ベース版)
|
||||||
///
|
///
|
||||||
/// Phase 32 L-1.2: 純粋な構造チェックのみ(関数名フィルタは lower() 側で適用)
|
/// Phase 32 L-1.4: ExitGroup ベースの判定に強化
|
||||||
///
|
///
|
||||||
/// # Case-A の定義
|
/// # Case-A の定義
|
||||||
///
|
///
|
||||||
/// - 単一出口(exits が 1 箇所以下)
|
/// - **単一出口グループ**: 全ての出口辺が同じターゲットブロックに向かう
|
||||||
|
/// (例: `if c != ' ' && c != '\t' { break }` は複数 ExitEdge だが、
|
||||||
|
/// 同じ exit ブロックに向かうので Case-A として許可)
|
||||||
|
/// - **非ローカル出口なし**: Return/Throw がない
|
||||||
/// - ヘッダブロックの succ が 2 つ(cond true/false)
|
/// - ヘッダブロックの succ が 2 つ(cond true/false)
|
||||||
/// - ループ変数または固定変数が存在
|
/// - ループ変数または固定変数が存在
|
||||||
/// - ネストループなし(将来チェック追加予定)
|
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `func`: MIR 関数(ヘッダ succ チェック用)
|
/// - `func`: MIR 関数(ヘッダ succ チェック用)
|
||||||
/// - `region`: LoopRegion(ブロック構造)
|
/// - `region`: LoopRegion(ブロック構造)
|
||||||
/// - `control`: LoopControlShape(制御フロー辺)
|
/// - `control`: LoopControlShape(制御フロー辺)
|
||||||
|
/// - `exit_edges`: ExitEdge のリスト(グループ化分析用)
|
||||||
/// - `scope`: LoopScopeShape(変数分類用)
|
/// - `scope`: LoopScopeShape(変数分類用)
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
@ -184,25 +223,39 @@ impl LoopToJoinLowerer {
|
|||||||
&self,
|
&self,
|
||||||
func: &MirFunction,
|
func: &MirFunction,
|
||||||
region: &LoopRegion,
|
region: &LoopRegion,
|
||||||
control: &LoopControlShape,
|
_control: &LoopControlShape, // Phase 32 L-1.4: ExitEdge ベースに移行したため未使用
|
||||||
|
exit_edges: &[ExitEdge],
|
||||||
scope: &LoopScopeShape,
|
scope: &LoopScopeShape,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Phase 32 L-1.2: 純粋な構造チェックのみ
|
// Phase 32 L-1.4: ExitAnalysis ベースの出口判定
|
||||||
// 関数名フィルタは lower() 側で generic_case_a_enabled() に応じて適用
|
let exit_analysis = analyze_exits(exit_edges);
|
||||||
|
|
||||||
// 1) 単一出口 (Case-A 限定: exits が 1 箇所以下)
|
// 1) 単一出口グループ + 非ローカル出口なし
|
||||||
// Note: break_targets ベースなので、条件 false による自然な出口は含まない
|
// 複数の ExitEdge でも、同じターゲットに向かうなら Case-A として許可
|
||||||
// 将来 Case-B/C で複数出口を許可する場合はここを緩める
|
if !exit_analysis.is_single_exit_group() {
|
||||||
if control.exits.len() > 1 {
|
|
||||||
if self.debug {
|
if self.debug {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[LoopToJoinLowerer] rejected: multiple exits ({}) - Case-A requires single exit",
|
"[LoopToJoinLowerer] rejected: not single exit group (groups={}, nonlocal={})",
|
||||||
control.exits.len()
|
exit_analysis.loop_exit_groups.len(),
|
||||||
|
exit_analysis.nonlocal_exits.len()
|
||||||
);
|
);
|
||||||
|
// 詳細ログ: 各グループのターゲットを出力
|
||||||
|
for (i, group) in exit_analysis.loop_exit_groups.iter().enumerate() {
|
||||||
|
eprintln!(
|
||||||
|
" group[{}]: target={:?}, edges={}, has_break={}",
|
||||||
|
i,
|
||||||
|
group.target,
|
||||||
|
group.edges.len(),
|
||||||
|
group.has_break
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: control.exits は ExitEdge の数(辺の数)なので、
|
||||||
|
// 複数でも単一グループなら OK という新しいロジック
|
||||||
|
|
||||||
// 2) ヘッダブロックの succ が 2 つ(cond true → body, cond false → exit)
|
// 2) ヘッダブロックの succ が 2 つ(cond true → body, cond false → exit)
|
||||||
// これにより while(cond) 形式のループのみを対象とする
|
// これにより while(cond) 形式のループのみを対象とする
|
||||||
if let Some(header_block) = func.blocks.get(®ion.header) {
|
if let Some(header_block) = func.blocks.get(®ion.header) {
|
||||||
@ -236,6 +289,18 @@ impl LoopToJoinLowerer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4) Phase 29 L-5.3: Progress carrier チェック
|
||||||
|
// 無限ループの可能性があるループを事前に弾く
|
||||||
|
if !Self::has_safe_progress(scope, func, region) {
|
||||||
|
if self.debug {
|
||||||
|
eprintln!(
|
||||||
|
"[LoopToJoinLowerer] rejected: no safe progress carrier (progress_carrier={:?})",
|
||||||
|
scope.progress_carrier
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user