feat(llvm): Phase 132-P0 - block_end_values tuple-key fix for cross-function isolation
## Problem `block_end_values` used block ID only as key, causing collisions when multiple functions share the same block IDs (e.g., bb0 in both condition_fn and main). ## Root Cause - condition_fn's bb0 → block_end_values[0] - main's bb0 → block_end_values[0] (OVERWRITES!) - PHI resolution gets wrong snapshot → dominance error ## Solution (Box-First principle) Change key from `int` to `Tuple[str, int]` (func_name, block_id): ```python # Before block_end_values: Dict[int, Dict[int, ir.Value]] # After block_end_values: Dict[Tuple[str, int], Dict[int, ir.Value]] ``` ## Files Modified (Python - 6 files) 1. `llvm_builder.py` - Type annotation update 2. `function_lower.py` - Pass func_name to lower_blocks 3. `block_lower.py` - Use tuple keys for snapshot save/load 4. `resolver.py` - Add func_name parameter to resolve_incoming 5. `wiring.py` - Thread func_name through PHI wiring 6. `phi_manager.py` - Debug traces ## Files Modified (Rust - cleanup) - Removed deprecated `loop_to_join.rs` (297 lines deleted) - Updated pattern lowerers for cleaner exit handling - Added lifecycle management improvements ## Verification - ✅ Pattern 1: VM RC: 3, LLVM Result: 3 (no regression) - ⚠️ Case C: Still has dominance error (separate root cause) - Needs additional scope fixes (phi_manager, resolver caches) ## Design Principles - **Box-First**: Each function is an isolated Box with scoped state - **SSOT**: (func_name, block_id) uniquely identifies block snapshots - **Fail-Fast**: No cross-function state contamination ## Known Issues (Phase 132-P1) Other function-local state needs same treatment: - phi_manager.predeclared - resolver caches (i64_cache, ptr_cache, etc.) - builder._jump_only_blocks ## Documentation - docs/development/current/main/investigations/phase132-p0-case-c-root-cause.md - docs/development/current/main/investigations/phase132-p0-tuple-key-implementation.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
73
src/mir/join_ir/lowering/loop_to_join/case_a_entrypoints.rs
Normal file
73
src/mir/join_ir/lowering/loop_to_join/case_a_entrypoints.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use super::LoopToJoinLowerer;
|
||||
use crate::mir::join_ir::JoinModule;
|
||||
use crate::mir::loop_form::LoopForm;
|
||||
use crate::mir::MirFunction;
|
||||
|
||||
impl LoopToJoinLowerer {
|
||||
/// Case-A 汎用 lowerer の「Main.skip/1 用」薄いラッパー。
|
||||
pub fn lower_case_a_for_skip_ws(
|
||||
&self,
|
||||
func: &MirFunction,
|
||||
loop_form: &LoopForm,
|
||||
) -> Option<JoinModule> {
|
||||
self.lower(func, loop_form, Some("Main.skip/1"))
|
||||
}
|
||||
|
||||
/// Case-A 汎用 lowerer の「FuncScannerBox.trim/1 用」薄いラッパー。
|
||||
pub fn lower_case_a_for_trim(
|
||||
&self,
|
||||
func: &MirFunction,
|
||||
loop_form: &LoopForm,
|
||||
) -> Option<JoinModule> {
|
||||
self.lower(func, loop_form, Some("FuncScannerBox.trim/1"))
|
||||
}
|
||||
|
||||
/// Case-A 汎用 lowerer の「FuncScannerBox.append_defs/2 用」薄いラッパー。
|
||||
pub fn lower_case_a_for_append_defs(
|
||||
&self,
|
||||
func: &MirFunction,
|
||||
loop_form: &LoopForm,
|
||||
) -> Option<JoinModule> {
|
||||
self.lower(func, loop_form, Some("FuncScannerBox.append_defs/2"))
|
||||
}
|
||||
|
||||
/// Case-A 汎用 lowerer の「Stage1UsingResolverBox.resolve_for_source/5 用」薄いラッパー。
|
||||
pub fn lower_case_a_for_stage1_resolver(
|
||||
&self,
|
||||
func: &MirFunction,
|
||||
loop_form: &LoopForm,
|
||||
) -> Option<JoinModule> {
|
||||
self.lower(
|
||||
func,
|
||||
loop_form,
|
||||
Some("Stage1UsingResolverBox.resolve_for_source/5"),
|
||||
)
|
||||
}
|
||||
|
||||
/// Case-A 汎用 lowerer の「StageBBodyExtractorBox.build_body_src/2 用」薄いラッパー。
|
||||
pub fn lower_case_a_for_stageb_body(
|
||||
&self,
|
||||
func: &MirFunction,
|
||||
loop_form: &LoopForm,
|
||||
) -> Option<JoinModule> {
|
||||
self.lower(
|
||||
func,
|
||||
loop_form,
|
||||
Some("StageBBodyExtractorBox.build_body_src/2"),
|
||||
)
|
||||
}
|
||||
|
||||
/// Case-A 汎用 lowerer の「StageBFuncScannerBox.scan_all_boxes/1 用」薄いラッパー。
|
||||
pub fn lower_case_a_for_stageb_funcscanner(
|
||||
&self,
|
||||
func: &MirFunction,
|
||||
loop_form: &LoopForm,
|
||||
) -> Option<JoinModule> {
|
||||
self.lower(
|
||||
func,
|
||||
loop_form,
|
||||
Some("StageBFuncScannerBox.scan_all_boxes/1"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
166
src/mir/join_ir/lowering/loop_to_join/core.rs
Normal file
166
src/mir/join_ir/lowering/loop_to_join/core.rs
Normal file
@ -0,0 +1,166 @@
|
||||
use crate::mir::control_form::LoopId;
|
||||
use crate::mir::join_ir::lowering::loop_form_intake::intake_loop_form;
|
||||
use crate::mir::join_ir::lowering::loop_pattern_validator::LoopPatternValidator;
|
||||
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
||||
use crate::mir::join_ir::lowering::loop_view_builder::LoopViewBuilder;
|
||||
use crate::mir::join_ir::JoinModule;
|
||||
use crate::mir::loop_form::LoopForm;
|
||||
use crate::mir::query::MirQueryBox;
|
||||
use crate::mir::MirFunction;
|
||||
|
||||
fn generic_case_a_enabled() -> bool {
|
||||
crate::mir::join_ir::env_flag_is_1("NYASH_JOINIR_LOWER_GENERIC")
|
||||
}
|
||||
|
||||
/// Loop→JoinIR 変換の統一箱(coordinator)
|
||||
///
|
||||
/// - MirQuery/Intake/LoopScopeShape の構築
|
||||
/// - Validator/Builder 呼び出しの調整
|
||||
/// - strict mode の fail-fast(対象関数のみ)
|
||||
pub struct LoopToJoinLowerer {
|
||||
debug: bool,
|
||||
validator: LoopPatternValidator,
|
||||
builder: LoopViewBuilder,
|
||||
}
|
||||
|
||||
impl Default for LoopToJoinLowerer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl LoopToJoinLowerer {
|
||||
pub fn new() -> Self {
|
||||
let debug = std::env::var("NYASH_LOOPTOJOIN_DEBUG")
|
||||
.map(|v| v == "1")
|
||||
.unwrap_or(false);
|
||||
Self {
|
||||
debug,
|
||||
validator: LoopPatternValidator::new(),
|
||||
builder: LoopViewBuilder::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// MIR LoopForm を JoinIR (JoinModule) に変換
|
||||
///
|
||||
/// - `Some(JoinModule)`: 変換成功
|
||||
/// - `None`: 未サポート(上位のフォールバックへ)
|
||||
pub fn lower(
|
||||
&self,
|
||||
func: &MirFunction,
|
||||
loop_form: &LoopForm,
|
||||
func_name: Option<&str>,
|
||||
) -> Option<JoinModule> {
|
||||
let strict_on = crate::config::env::joinir_strict_enabled();
|
||||
let is_minimal_target = func_name
|
||||
.map(super::super::loop_scope_shape::is_case_a_minimal_target)
|
||||
.unwrap_or(false);
|
||||
|
||||
if self.debug {
|
||||
eprintln!(
|
||||
"[LoopToJoinLowerer] lower() called for {:?}",
|
||||
func_name.unwrap_or("<unknown>")
|
||||
);
|
||||
}
|
||||
|
||||
let query = MirQueryBox::new(func);
|
||||
let intake = intake_loop_form(loop_form, &query, func)?;
|
||||
let scope = LoopScopeShape::from_loop_form(loop_form, &intake, &query, func_name)?;
|
||||
|
||||
if self.debug {
|
||||
eprintln!(
|
||||
"[LoopToJoinLowerer] LoopScopeShape built: pinned={:?}, carriers={:?}, exit_live={:?}",
|
||||
scope.pinned, scope.carriers, scope.exit_live
|
||||
);
|
||||
}
|
||||
|
||||
let loop_id = LoopId(0);
|
||||
let region = loop_form.to_region_view(loop_id);
|
||||
let exit_edges = loop_form.to_exit_edges(loop_id);
|
||||
|
||||
if self.debug {
|
||||
eprintln!(
|
||||
"[LoopToJoinLowerer] views: func={:?} loop_id={:?} header={:?} exits={:?}",
|
||||
func_name.unwrap_or("<unknown>"),
|
||||
loop_id,
|
||||
region.header,
|
||||
exit_edges.iter().map(|e| e.to).collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
if !self
|
||||
.validator
|
||||
.is_supported_case_a(func, ®ion, &exit_edges, &scope)
|
||||
{
|
||||
if self.debug {
|
||||
eprintln!(
|
||||
"[LoopToJoinLowerer] rejected by validator: {:?}",
|
||||
func_name.unwrap_or("<unknown>")
|
||||
);
|
||||
}
|
||||
if strict_on && is_minimal_target {
|
||||
panic!(
|
||||
"[joinir/loop] strict mode: validator rejected {}",
|
||||
func_name.unwrap_or("<unknown>")
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
if !generic_case_a_enabled() {
|
||||
if !func_name
|
||||
.map_or(false, super::super::loop_scope_shape::is_case_a_minimal_target)
|
||||
{
|
||||
if self.debug {
|
||||
eprintln!(
|
||||
"[LoopToJoinLowerer] rejected by name filter (generic disabled): {:?}",
|
||||
func_name.unwrap_or("<unknown>")
|
||||
);
|
||||
}
|
||||
if strict_on && is_minimal_target {
|
||||
panic!(
|
||||
"[joinir/loop] strict mode: name filter rejected {}",
|
||||
func_name.unwrap_or("<unknown>")
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
} else if self.debug {
|
||||
eprintln!(
|
||||
"[LoopToJoinLowerer] generic Case-A enabled, allowing {:?}",
|
||||
func_name.unwrap_or("<unknown>")
|
||||
);
|
||||
}
|
||||
|
||||
let out = self.builder.build(scope, func_name);
|
||||
if out.is_none() && strict_on && is_minimal_target {
|
||||
panic!(
|
||||
"[joinir/loop] strict mode: lowering failed for {}",
|
||||
func_name.unwrap_or("<unknown>")
|
||||
);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// 旧コメント/ドキュメントとの整合のための別名(導線の明確化)
|
||||
pub fn lower_loop(
|
||||
&self,
|
||||
func: &MirFunction,
|
||||
loop_form: &LoopForm,
|
||||
func_name: Option<&str>,
|
||||
) -> Option<JoinModule> {
|
||||
self.lower(func, loop_form, func_name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_lowerer_creation() {
|
||||
let lowerer = LoopToJoinLowerer::new();
|
||||
assert!(!lowerer.debug || lowerer.debug);
|
||||
}
|
||||
}
|
||||
|
||||
19
src/mir/join_ir/lowering/loop_to_join/mod.rs
Normal file
19
src/mir/join_ir/lowering/loop_to_join/mod.rs
Normal file
@ -0,0 +1,19 @@
|
||||
//! Phase 31/33-23: Loop→JoinIR lowering entry (LoopToJoinLowerer)
|
||||
//!
|
||||
//! このモジュールは「LoopForm を JoinIR (JoinModule) に変換する統一エントリ」を提供する。
|
||||
//! 本体ロジックは coordinator に集約し、責務を分割して保守性を上げる。
|
||||
//!
|
||||
//! ## 責務境界(Box化)
|
||||
//! - `LoopPatternValidator`(`../loop_pattern_validator.rs`): 構造検証(shape guard)
|
||||
//! - `LoopViewBuilder`(`../loop_view_builder.rs`): lowerer 選択(routing)
|
||||
//! - `LoopToJoinLowerer`(このモジュール): intake/scope 構築と strict ハンドリング(coordinator)
|
||||
//!
|
||||
//! ## 注意
|
||||
//! - Phase 進捗ログはここに混ぜない(現役の導線のみ)。
|
||||
//! - “とりあえず通す”フォールバックは増やさない。失敗は `None` で上位に返す。
|
||||
|
||||
mod core;
|
||||
mod case_a_entrypoints;
|
||||
|
||||
pub use core::LoopToJoinLowerer;
|
||||
|
||||
Reference in New Issue
Block a user