feat(control_tree): Phase 131 P1.5-P2 DirectValue exit reconnection
Implement DirectValue mode for Normalized shadow exit handling:
**P1.5 Changes**:
- Add ExitReconnectMode::DirectValue (skip exit PHI generation)
- Carry remapped_exit_values through merge result
- Update host variable_map directly with exit values
- Fix loop(true) { x = 1; break }; return x to return 1 correctly
**P2 Changes**:
- Normalize k_exit continuation entry/exit edges
- Rewrite TailCall(k_exit) → Jump(exit_block) for proper merge
- Add verify_all_terminator_targets_exist contract check
- Extend ExitLineReconnector to handle DirectValue mode
**Infrastructure**:
- tools/build_llvm.sh: Force TMPDIR under target/ (EXDEV mitigation)
- llvm_exe_runner.sh: Add exit_code verification support
- Phase 131 smokes: Update for dev-only + exit code validation
**Contracts**:
- PHI-free: Normalized path uses continuations only
- Exit values reconnect via remapped ValueIds
- Existing patterns unaffected (既定挙動不変)
Related: Phase 131 loop(true) break-once Normalized support
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -91,6 +91,48 @@ pub enum CarrierInit {
|
||||
LoopLocalZero,
|
||||
}
|
||||
|
||||
/// Phase 131 P1.5: Exit reconnection mode for JoinInlineBoundary
|
||||
///
|
||||
/// Controls whether exit values are reconnected via PHI generation or direct assignment.
|
||||
/// This separates Normalized shadow (DirectValue) from existing loop patterns (Phi).
|
||||
///
|
||||
/// # Design Principle (SSOT)
|
||||
///
|
||||
/// - **DirectValue**: Normalized loops prohibit PHI generation. Exit values are directly
|
||||
/// wired to variable_map using remapped_exit_values from MergeResult.
|
||||
/// - **Phi**: Existing loop patterns use PHI generation for exit value merging.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// // Normalized shadow: loop(true) { x = 1; break } → DirectValue
|
||||
/// JoinInlineBoundary { exit_reconnect_mode: ExitReconnectMode::DirectValue, .. }
|
||||
///
|
||||
/// // Traditional loop: loop(i < 3) { sum = sum + i } → Phi
|
||||
/// JoinInlineBoundary { exit_reconnect_mode: ExitReconnectMode::Phi, .. }
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ExitReconnectMode {
|
||||
/// Existing loop patterns: PHI generation for exit value merging
|
||||
///
|
||||
/// Used by Pattern 1-4 loops with multiple exit paths.
|
||||
/// Exit values are collected into exit PHIs.
|
||||
Phi,
|
||||
|
||||
/// Normalized shadow: Direct variable_map update, no PHI generation
|
||||
///
|
||||
/// Used by loop(true) { <assign>*; break } pattern.
|
||||
/// Exit values are directly wired using MergeResult.remapped_exit_values.
|
||||
DirectValue,
|
||||
}
|
||||
|
||||
impl Default for ExitReconnectMode {
|
||||
/// Default to Phi mode for backward compatibility
|
||||
fn default() -> Self {
|
||||
Self::Phi
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 229: ConditionAlias removed - redundant with promoted_loopbodylocals
|
||||
// The naming convention (old_name → "is_<old_name>" or "is_<old_name>_match")
|
||||
// is sufficient to resolve promoted variables dynamically.
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
//! ...
|
||||
//! ```
|
||||
|
||||
use super::carrier_info::CarrierRole;
|
||||
use super::carrier_info::{CarrierRole, ExitReconnectMode};
|
||||
use crate::mir::ValueId;
|
||||
|
||||
/// Explicit binding between JoinIR exit value and host variable
|
||||
@ -257,6 +257,15 @@ pub struct JoinInlineBoundary {
|
||||
/// - `Some(CarrierInfo)`: Full carrier metadata available
|
||||
/// - `None`: Legacy path (derive carriers from exit_bindings)
|
||||
pub carrier_info: Option<super::carrier_info::CarrierInfo>,
|
||||
|
||||
/// Phase 131 P1.5: Exit reconnection mode
|
||||
///
|
||||
/// Controls whether exit values are reconnected via PHI generation (Phi)
|
||||
/// or direct variable_map update (DirectValue).
|
||||
///
|
||||
/// - `Phi` (default): Existing loop patterns use exit PHI generation
|
||||
/// - `DirectValue`: Normalized shadow uses direct value wiring
|
||||
pub exit_reconnect_mode: ExitReconnectMode,
|
||||
}
|
||||
|
||||
impl JoinInlineBoundary {
|
||||
@ -284,6 +293,7 @@ impl JoinInlineBoundary {
|
||||
expr_result: None, // Phase 33-14: Default to carrier-only pattern
|
||||
loop_var_name: None, // Phase 33-16
|
||||
carrier_info: None, // Phase 228: Default to None
|
||||
exit_reconnect_mode: ExitReconnectMode::default(), // Phase 131 P1.5: Default to Phi
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,6 +337,7 @@ impl JoinInlineBoundary {
|
||||
expr_result: None, // Phase 33-14
|
||||
loop_var_name: None, // Phase 33-16
|
||||
carrier_info: None, // Phase 228
|
||||
exit_reconnect_mode: ExitReconnectMode::default(), // Phase 131 P1.5: Default to Phi
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,6 +398,7 @@ impl JoinInlineBoundary {
|
||||
expr_result: None, // Phase 33-14
|
||||
loop_var_name: None, // Phase 33-16
|
||||
carrier_info: None, // Phase 228
|
||||
exit_reconnect_mode: ExitReconnectMode::default(), // Phase 131 P1.5: Default to Phi
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,6 +445,7 @@ impl JoinInlineBoundary {
|
||||
expr_result: None, // Phase 33-14
|
||||
loop_var_name: None, // Phase 33-16
|
||||
carrier_info: None, // Phase 228
|
||||
exit_reconnect_mode: ExitReconnectMode::default(), // Phase 131 P1.5: Default to Phi
|
||||
}
|
||||
}
|
||||
|
||||
@ -483,6 +496,7 @@ impl JoinInlineBoundary {
|
||||
expr_result: None, // Phase 33-14
|
||||
loop_var_name: None, // Phase 33-16
|
||||
carrier_info: None, // Phase 228
|
||||
exit_reconnect_mode: ExitReconnectMode::default(), // Phase 131 P1.5: Default to Phi
|
||||
}
|
||||
}
|
||||
|
||||
@ -540,6 +554,7 @@ impl JoinInlineBoundary {
|
||||
expr_result: None, // Phase 33-14
|
||||
loop_var_name: None, // Phase 33-16
|
||||
carrier_info: None, // Phase 228
|
||||
exit_reconnect_mode: ExitReconnectMode::default(), // Phase 131 P1.5: Default to Phi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +82,7 @@ pub struct JoinInlineBoundaryBuilder {
|
||||
impl JoinInlineBoundaryBuilder {
|
||||
/// Create a new builder with default empty boundary
|
||||
pub fn new() -> Self {
|
||||
use crate::mir::join_ir::lowering::carrier_info::ExitReconnectMode;
|
||||
Self {
|
||||
boundary: JoinInlineBoundary {
|
||||
join_inputs: vec![],
|
||||
@ -96,6 +97,7 @@ impl JoinInlineBoundaryBuilder {
|
||||
expr_result: None,
|
||||
loop_var_name: None,
|
||||
carrier_info: None, // Phase 228: Initialize as None
|
||||
exit_reconnect_mode: ExitReconnectMode::default(), // Phase 131 P1.5
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user