feat(joinir): Phase 33-14 JoinFragmentMeta for expr/carrier separation
Introduces JoinFragmentMeta to distinguish between loop expression results and carrier variable updates, fixing SSA correctness issues. ## Changes ### New: JoinFragmentMeta struct (carrier_info.rs) - `expr_result: Option<ValueId>` - Loop as expression (return loop(...)) - `exit_meta: ExitMeta` - Carrier updates for variable_map - Helper methods: with_expr_result(), carrier_only(), empty() ### Pattern 2 Lowerer Updates - loop_with_break_minimal.rs: Returns (JoinModule, JoinFragmentMeta) - pattern2_with_break.rs: Sets boundary.expr_result from fragment_meta ### instruction_rewriter.rs - Phase 33-14: Only add to exit_phi_inputs when boundary.expr_result is Some - Phase 33-13: MergeResult struct with carrier_inputs map ### JoinInlineBoundary (inline_boundary.rs) - New field: expr_result: Option<ValueId> - All constructors updated with expr_result: None default ## Design Philosophy Previously, exit_phi_inputs mixed expr results with carrier updates, causing: - PHI inputs referencing undefined remapped values - SSA-undef errors in VM execution With JoinFragmentMeta: - expr_result → exit_phi_inputs (generates PHI for expr value) - exit_meta → carrier_inputs (updates variable_map via carrier PHIs) ## Test Results - Pattern 1 (carrier-only): Works correctly (no exit_phi_inputs) - Pattern 2 (expr result): Design complete, SSA-undef fix deferred to Phase 33-15 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -387,6 +387,8 @@ mod tests {
|
||||
join_outputs: vec![],
|
||||
exit_bindings: vec![], // Phase 171: Add missing field
|
||||
condition_inputs: vec![], // Phase 171: Add missing field
|
||||
condition_bindings: vec![], // Phase 171-fix: Add missing field
|
||||
expr_result: None, // Phase 33-14: Add missing field
|
||||
};
|
||||
|
||||
builder.apply_to_boundary(&mut boundary)
|
||||
|
||||
@ -142,8 +142,8 @@ impl MirBuilder {
|
||||
};
|
||||
|
||||
// Phase 169 / Phase 171-fix / Phase 172-3: Call Pattern 2 lowerer with ConditionEnv
|
||||
// Now returns (JoinModule, ExitMeta) for proper exit_bindings construction
|
||||
let (join_module, exit_meta) = match lower_loop_with_break_minimal(scope, condition, &env, &loop_var_name) {
|
||||
// Phase 33-14: Now returns (JoinModule, JoinFragmentMeta) for expr_result + carrier separation
|
||||
let (join_module, fragment_meta) = match lower_loop_with_break_minimal(scope, condition, &env, &loop_var_name) {
|
||||
Ok((module, meta)) => (module, meta),
|
||||
Err(e) => {
|
||||
// Phase 195: Use unified trace
|
||||
@ -152,6 +152,9 @@ impl MirBuilder {
|
||||
}
|
||||
};
|
||||
|
||||
// Phase 33-14: Extract exit_meta from fragment_meta for backward compatibility
|
||||
let exit_meta = &fragment_meta.exit_meta;
|
||||
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().joinir_stats(
|
||||
"pattern2",
|
||||
@ -186,12 +189,14 @@ impl MirBuilder {
|
||||
let exit_bindings = ExitMetaCollector::collect(self, &exit_meta, debug);
|
||||
|
||||
// Phase 172-3: Build boundary with both condition_bindings and exit_bindings
|
||||
// Phase 33-14: Set expr_result from fragment_meta
|
||||
let mut boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_inputs_only(
|
||||
vec![ValueId(0)], // JoinIR's main() parameter (loop variable init)
|
||||
vec![loop_var_id], // Host's loop variable
|
||||
);
|
||||
boundary.condition_bindings = condition_bindings;
|
||||
boundary.exit_bindings = exit_bindings.clone();
|
||||
boundary.expr_result = fragment_meta.expr_result; // Phase 33-14: Pass expr_result to merger
|
||||
|
||||
// Phase 189: Capture exit PHI result (now used for reconnect)
|
||||
let _ = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?;
|
||||
|
||||
Reference in New Issue
Block a user