diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 455864f8..0de4215d 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -237,7 +237,7 @@ Update (2025-11-16 — Phase 25.1b: selfhost builder multi-carrier & BoxTypeInsp - さらに Rust VM 側の `MirInterpreter::reg_load` に開発用の追加情報を付けたことで、`Invalid value: use of undefined value ValueId(N)` が発生した際に `fn` / `last_block` / `last_inst` がエラーメッセージに含まれるようになり、Stage‑B Main.main 内の `ParserBox.length()` 呼び出しが recv 未定義で落ちていることを特定できるようになった(NYASH_VM_TRACE/NYASH_VM_TRACE_EXEC 未設定時でも場所が分かる)。 - なお、Stage‑B を selfhost CLI サンプルに対して実行した際に現時点で見えている残存課題は次の 2 点: - 1) `if args { ... }` まわりの truthy 判定(ArrayBox を boolean 条件に使っている部分)の扱いに起因する型エラーであり、これは SSA ではなく「条件式の型/truthy 規約」をどう定義するかという別問題として扱う(Phase 25.1c 以降の型システム整理タスクで扱う想定)。 - - 2) Rust VM 実行時に `❌ VM error: Invalid value: use of undefined value ValueId(17)` が発生しており、拡張したエラーメッセージ(初期段階では `fn=Main.main`、Stage‑B 箱分割後は `fn=StageBArgsBox.resolve_src/1` として報告)から「Stage‑B パスにおける `ParserBox.length()` 呼び出しで Method recv(ValueId(17)) が適切に定義されていない」ことが判明している。Task先生の調査では、loop header/body の PHI 生成まわりで pinned スロットに対して循環依存する入力(例: `bb6` 内で `%17 = phi[%14,bb3,...]` かつ `%14` 自体が同じ `bb6` の後続で定義される)があり、Use-before-def ではなく「PHI 入力の cycle」に近い構造バグであることが分かっている。これは verifier (`NYASH_VM_VERIFY_MIR=1`) が現状まだ検出していない「Callee.receiver 側+PHI 配線」の問題であり、Phase 25.1c の Stage‑B / LoopBuilder / LocalSSA 整理タスクの中で (a) MethodCall の recv に対しても `Undefined value` 検査を掛ける、(b) loop_phi / pinned 変数の PHI 配線を修正して循環入力を構造的に防ぐ、という方針で扱う想定。 + - 2) Rust VM 実行時に `❌ VM error: Invalid value: use of undefined value ValueId(17)` が発生しており、拡張したエラーメッセージ(初期段階では `fn=Main.main`、Stage‑B 箱分割後は `fn=StageBArgsBox.resolve_src/1` として報告)から「Stage‑B パスにおける `ParserBox.length()` 呼び出しで Method recv(ValueId(17)) が適切に定義されていない」ことが判明している。Task先生+Claude code 君の調査では、loop header/body の PHI 生成まわりで pinned スロットに対して循環依存する入力(例: あるループで header から body への PHI が `%17 = phi[%14,bb3,...]` を持つ一方で `%14` 自体は同じ `bb6` 内の後続で定義される)になっているケースがあり、Use-before-def というより「PHI 入力の cycle」に近い構造バグであることが分かっている。また、LoopForm v2 の prototype では preheader 専用ブロックを導入し、`prepare_structure` 時点で `current_vars` における `args` が preheader 手前では `ValueId(0)`(関数パラメータの本来の値)、`prepare_structure` 呼び出し直前には `ValueId(1)` に変わってしまっていることも確認されており、`new_block` / `emit_jump` / variable_map 更新のどこかで pinned/キャリア変数の初期値がずれている疑いが強い。この一連の問題は verifier (`NYASH_VM_VERIFY_MIR=1`) が現状まだ検出していない「Callee.receiver 側+PHI 配線」の問題であり、Phase 25.1c の Stage‑B / LoopBuilder / LocalSSA 整理タスクの中で (a) MethodCall の recv に対しても `Undefined value` 検査を掛ける、(b) loop_phi / LoopFormBuilder / pinned 変数の PHI 配線を修正して循環入力を構造的に防ぐ、(c) preheader 専用ブロックと variable_map スナップショットを使った LoopForm v2 の統合方針を検討する、という流れで扱う想定。 - Next tasks (Phase 25.1b → 25.1c handoff / Codex): 1. Rust 層 Call/ExternCall 契約のドキュメント固定(Step 4.1) - `src/mir/builder/builder_calls.rs` / `src/backend/mir_interpreter/handlers/{calls,externs,extern_provider}.rs` / `src/runtime/plugin_loader_v2/enabled/extern_functions.rs` をベースに、「MethodCall/ExternCall/hostbridge.extern_invoke/ env.codegen/env.mirbuilder」の SSOT を Phase 25.1b README に記録(実施済み)。 diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index df6ec80d..acae56f2 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -137,26 +137,46 @@ impl<'a> LoopBuilder<'a> { condition: ASTNode, body: Vec, ) -> Result { - // Create loop structure blocks - let preheader_id = self.current_block()?; + // Create loop structure blocks following LLVM canonical form + // We need a dedicated preheader block to materialize loop entry copies + let before_loop_id = self.current_block()?; + + // Capture variable snapshot BEFORE creating new blocks (at loop entry point) + let current_vars = self.get_current_variable_map(); + + if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() { + eprintln!("[loopform] before_loop_id={:?}, variable_map size={}", + before_loop_id, current_vars.len()); + for (name, value) in ¤t_vars { + eprintln!(" {} -> {:?}", name, value); + } + } + + let preheader_id = self.new_block(); let header_id = self.new_block(); let body_id = self.new_block(); let latch_id = self.new_block(); let exit_id = self.new_block(); + // Jump from current block to preheader + self.emit_jump(preheader_id)?; + // Initialize LoopFormBuilder with preheader and header blocks let mut loopform = LoopFormBuilder::new(preheader_id, header_id); - // Capture current variable map snapshot at preheader - let current_vars = self.get_current_variable_map(); - // Pass 1: Prepare structure (allocate all ValueIds upfront) if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() { - eprintln!("[loopform] variable_map at loop entry:"); + eprintln!("[loopform] Block IDs: preheader={:?}, header={:?}, body={:?}, latch={:?}, exit={:?}", + preheader_id, header_id, body_id, latch_id, exit_id); + eprintln!("[loopform] variable_map at loop entry (size={}):", current_vars.len()); + let mut loop_count = 0; for (name, value) in ¤t_vars { + loop_count += 1; + eprintln!(" [{}] {} -> {:?}", loop_count, name, value); let is_param = self.is_parameter(name); - eprintln!(" {} -> {:?} (param={})", name, value, is_param); + eprintln!(" param={}", is_param); } + eprintln!("[loopform] iterated {} times", loop_count); } loopform.prepare_structure(self, ¤t_vars)?;