diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs b/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs index ddaa7ff8..3873f191 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs @@ -112,11 +112,31 @@ impl MirBuilder { "[cf_loop/pattern3] if-sum pattern detected but no if statement found".to_string() })?; - // Call AST-based if-sum lowerer + // Phase 220-D: Build ConditionEnv for variable resolution + use super::condition_env_builder::ConditionEnvBuilder; + let loop_var_name = ctx.loop_var_name.clone(); + let loop_var_id = ctx.loop_var_id; + + let (cond_env, condition_bindings, _loop_var_join_id) = + ConditionEnvBuilder::build_for_break_condition_v2( + condition, + &loop_var_name, + &self.variable_map, + loop_var_id, + &mut join_value_space, + )?; + + eprintln!("[pattern3/if-sum] Phase 220-D: ConditionEnv has {} bindings", condition_bindings.len()); + for binding in &condition_bindings { + eprintln!(" '{}': HOST {:?} → JoinIR {:?}", binding.name, binding.host_value, binding.join_value); + } + + // Call AST-based if-sum lowerer with ConditionEnv let (join_module, fragment_meta) = lower_if_sum_pattern( condition, if_stmt, body, + &cond_env, &mut join_value_space, )?; @@ -174,8 +194,10 @@ impl MirBuilder { ); // Phase 215-2: Pass expr_result to boundary + // Phase 220-D: Pass condition_bindings for variable remapping let mut boundary_builder = JoinInlineBoundaryBuilder::new() .with_inputs(join_inputs, host_inputs) + .with_condition_bindings(condition_bindings) // Phase 220-D: Map condition-only vars .with_exit_bindings(exit_bindings) .with_loop_var_name(Some(ctx.loop_var_name.clone())); diff --git a/src/mir/join_ir/lowering/loop_with_if_phi_if_sum.rs b/src/mir/join_ir/lowering/loop_with_if_phi_if_sum.rs index 890a5151..4ece3956 100644 --- a/src/mir/join_ir/lowering/loop_with_if_phi_if_sum.rs +++ b/src/mir/join_ir/lowering/loop_with_if_phi_if_sum.rs @@ -30,7 +30,10 @@ use crate::ast::ASTNode; use crate::mir::join_ir::lowering::carrier_info::{ExitMeta, JoinFragmentMeta}; +use crate::mir::join_ir::lowering::condition_env::ConditionEnv; +use crate::mir::join_ir::lowering::condition_lowerer::lower_value_expression; use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace; +use crate::mir::ValueId; use crate::mir::join_ir::{ BinOpKind, CompareOp, ConstValue, JoinFuncId, JoinFunction, JoinInst, JoinModule, MirLikeInst, UnaryOp, @@ -43,6 +46,7 @@ use crate::mir::join_ir::{ /// * `loop_condition` - Loop condition AST (e.g., `i < len`) /// * `if_stmt` - If statement AST from loop body /// * `body` - Full loop body AST (for finding counter update) +/// * `cond_env` - ConditionEnv for variable resolution (Phase 220-D) /// * `join_value_space` - Unified ValueId allocator /// /// # Returns @@ -53,17 +57,26 @@ pub fn lower_if_sum_pattern( loop_condition: &ASTNode, if_stmt: &ASTNode, body: &[ASTNode], + cond_env: &ConditionEnv, join_value_space: &mut JoinValueSpace, ) -> Result<(JoinModule, JoinFragmentMeta), String> { eprintln!("[joinir/pattern3/if-sum] Starting AST-based if-sum lowering"); - // Step 1: Extract loop condition info (e.g., i < len → var="i", op=Lt, limit=len) - let (loop_var, loop_op, loop_limit) = extract_loop_condition(loop_condition)?; - eprintln!("[joinir/pattern3/if-sum] Loop condition: {} {:?} {}", loop_var, loop_op, loop_limit); + // Allocator for extracting condition values + let mut alloc_value = || join_value_space.alloc_local(); - // Step 2: Extract if condition info (e.g., i > 0 → var="i", op=Gt, value=0) - let (if_var, if_op, if_value) = extract_if_condition(if_stmt)?; - eprintln!("[joinir/pattern3/if-sum] If condition: {} {:?} {}", if_var, if_op, if_value); + // Step 1: Extract loop condition info (e.g., i < len → var="i", op=Lt, limit=ValueId) + // Phase 220-D: Now returns ValueId and instructions for limit + // Uses cond_env for variable resolution (e.g., `len` in `i < len`) + let (loop_var, loop_op, loop_limit_val, loop_limit_insts) = + extract_loop_condition(loop_condition, &mut alloc_value, cond_env)?; + eprintln!("[joinir/pattern3/if-sum] Loop condition: {} {:?} ValueId({})", loop_var, loop_op, loop_limit_val.0); + + // Step 2: Extract if condition info (e.g., i > 0 → var="i", op=Gt, value=ValueId) + // Phase 220-D: Now returns ValueId and instructions + let (if_var, if_op, if_value_val, if_value_insts) = + extract_if_condition(if_stmt, &mut alloc_value, cond_env)?; + eprintln!("[joinir/pattern3/if-sum] If condition: {} {:?} ValueId({})", if_var, if_op, if_value_val.0); // Step 3: Extract then-branch update (e.g., sum = sum + 1 → var="sum", addend=1) let (update_var, update_addend) = extract_then_update(if_stmt)?; @@ -95,11 +108,10 @@ pub fn lower_if_sum_pattern( let count_param = alloc_value(); // loop_step locals - let loop_limit_val = alloc_value(); // loop limit value + // Phase 220-D: loop_limit_val and if_value_val are already allocated by extract_*_condition() + // and will be used directly from their return values let cmp_loop = alloc_value(); // loop condition comparison let exit_cond = alloc_value(); // negated loop condition - - let if_const = alloc_value(); // if condition constant let if_cmp = alloc_value(); // if condition comparison let sum_then = alloc_value(); // sum + update_addend let count_const = alloc_value(); // count increment (1) @@ -159,11 +171,11 @@ pub fn lower_if_sum_pattern( ); // --- Exit Condition Check --- - // Load loop limit from AST - loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Const { - dst: loop_limit_val, - value: ConstValue::Integer(loop_limit), - })); + // Phase 220-D: Prepend loop limit instructions (generated from AST) + // This handles both literals (Const) and variables (from ConditionEnv) + for inst in loop_limit_insts { + loop_step_func.body.push(inst); + } // Compare: i < limit (or other op from AST) loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Compare { @@ -188,18 +200,17 @@ pub fn lower_if_sum_pattern( }); // --- If Condition (AST-based) --- - // Load if constant - loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Const { - dst: if_const, - value: ConstValue::Integer(if_value), - })); + // Phase 220-D: Prepend if value instructions (generated from AST) + for inst in if_value_insts { + loop_step_func.body.push(inst); + } // Compare: if_var if_value loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Compare { dst: if_cmp, op: if_op, lhs: i_param, // Assuming if_var == loop_var (common case) - rhs: if_const, + rhs: if_value_val, })); // --- Then Branch --- @@ -312,8 +323,8 @@ pub fn lower_if_sum_pattern( let fragment_meta = JoinFragmentMeta::with_expr_result(sum_final, exit_meta); eprintln!("[joinir/pattern3/if-sum] Generated AST-based JoinIR"); - eprintln!("[joinir/pattern3/if-sum] Loop: {} {:?} {}", loop_var, loop_op, loop_limit); - eprintln!("[joinir/pattern3/if-sum] If: {} {:?} {}", if_var, if_op, if_value); + eprintln!("[joinir/pattern3/if-sum] Loop: {} {:?} ValueId({})", loop_var, loop_op, loop_limit_val.0); + eprintln!("[joinir/pattern3/if-sum] If: {} {:?} ValueId({})", if_var, if_op, if_value_val.0); eprintln!("[joinir/pattern3/if-sum] Phase 215-2: expr_result={:?}", sum_final); Ok((join_module, fragment_meta)) @@ -321,12 +332,35 @@ pub fn lower_if_sum_pattern( /// Extract loop condition: variable, operator, and limit /// +/// Phase 220-D: Now supports both literals and variables via ConditionEnv. +/// /// Supports: `var < lit`, `var <= lit`, `var > lit`, `var >= lit` -fn extract_loop_condition(cond: &ASTNode) -> Result<(String, CompareOp, i64), String> { +/// Supports: `var < var2`, `var <= var2`, etc. +/// +/// # Returns +/// +/// * `Ok((var_name, op, limit_value, limit_instructions))` where: +/// - `var_name`: Loop variable name (e.g., "i") +/// - `op`: Comparison operator +/// - `limit_value`: ValueId for the limit (either from literal or variable lookup) +/// - `limit_instructions`: JoinIR instructions to generate limit_value +fn extract_loop_condition( + cond: &ASTNode, + alloc_value: &mut F, + cond_env: &ConditionEnv, +) -> Result<(String, CompareOp, ValueId, Vec), String> +where + F: FnMut() -> ValueId, +{ match cond { ASTNode::BinaryOp { operator, left, right, .. } => { let var_name = extract_variable_name(left)?; - let limit = extract_integer_literal(right)?; + + // Lower the right-hand side (limit) using condition_lowerer + // This handles both literals and variables via ConditionEnv + let mut limit_instructions = Vec::new(); + let limit_value = lower_value_expression(right, alloc_value, cond_env, &mut limit_instructions)?; + let op = match operator { crate::ast::BinaryOperator::Less => CompareOp::Lt, crate::ast::BinaryOperator::LessEqual => CompareOp::Le, @@ -334,17 +368,27 @@ fn extract_loop_condition(cond: &ASTNode) -> Result<(String, CompareOp, i64), St crate::ast::BinaryOperator::GreaterEqual => CompareOp::Ge, _ => return Err(format!("[if-sum] Unsupported loop condition operator: {:?}", operator)), }; - Ok((var_name, op, limit)) + + Ok((var_name, op, limit_value, limit_instructions)) } _ => Err("[if-sum] Loop condition must be a binary comparison".to_string()), } } /// Extract if condition: variable, operator, and value -fn extract_if_condition(if_stmt: &ASTNode) -> Result<(String, CompareOp, i64), String> { +/// +/// Phase 220-D: Now supports variables via ConditionEnv +fn extract_if_condition( + if_stmt: &ASTNode, + alloc_value: &mut F, + cond_env: &ConditionEnv, +) -> Result<(String, CompareOp, ValueId, Vec), String> +where + F: FnMut() -> ValueId, +{ match if_stmt { ASTNode::If { condition, .. } => { - extract_loop_condition(condition) // Same format + extract_loop_condition(condition, alloc_value, cond_env) // Same format } _ => Err("[if-sum] Expected If statement".to_string()), } @@ -407,14 +451,12 @@ fn extract_variable_name(node: &ASTNode) -> Result { } /// Extract integer literal from AST node +/// +/// Phase 220-D: This function is now only used for simple updates (e.g., `sum + 1`). +/// For condition values, use `lower_value_expression()` which supports variables. fn extract_integer_literal(node: &ASTNode) -> Result { match node { ASTNode::Literal { value: crate::ast::LiteralValue::Integer(n), .. } => Ok(*n), - ASTNode::Variable { name, .. } => { - // Handle variable reference (e.g., `len`) - // For Phase 213, we only support literals. Variables need Phase 214+ - Err(format!("[if-sum] Variable '{}' in condition not supported yet (Phase 214+)", name)) - } _ => Err(format!("[if-sum] Expected integer literal, got {:?}", node)), } }