From bcdad203f0ed473671ab3fb9ea077b1f550c32c1 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Wed, 10 Dec 2025 09:23:44 +0900 Subject: [PATCH] feat(joinir): Phase 222-3 if-sum normalization integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 222: If Condition Normalization - Part 3 Goal: Integrate normalization into if-sum pattern detection and lowering Changes: 1. pattern_pipeline.rs (is_if_sum_pattern): - Updated to use analyze_condition_pattern() + normalize_comparison() - Added two-step validation: (a) Pattern must be SimpleComparison (b) Condition must be normalizable - Replaced is_simple_comparison() with Phase 222 API 2. loop_with_if_phi_if_sum.rs (extract_loop_condition): - Added Phase 222 normalization - Normalize condition to canonical form (var on left) - Support both literal and variable on right-hand side - Added mir::CompareOp → join_ir::CompareOp conversion - Handles: * Phase 219: var CmpOp literal (e.g., i > 0) * Phase 222: literal CmpOp var (e.g., 0 < i) → normalized * Phase 222: var CmpOp var (e.g., i > j) Status: Integration complete, ready for E2E testing Next: Phase 222-4 - verify regression tests and add new test cases --- .../joinir/patterns/pattern_pipeline.rs | 17 +++++- .../lowering/loop_with_if_phi_if_sum.rs | 56 +++++++++++++------ 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs b/src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs index ea3004cb..1f1a1bd3 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs @@ -189,14 +189,25 @@ impl PatternPipelineContext { return false; } - // Phase 219-fix: Check if if condition is a simple comparison + // Phase 222: Check if if condition is a simple comparison and normalizable // Complex conditions (e.g., i % 2 == 1) → fallback to legacy mode if let Some(ASTNode::If { condition, .. }) = if_stmt { - use crate::mir::join_ir::lowering::condition_pattern::is_simple_comparison; - if !is_simple_comparison(condition) { + use crate::mir::join_ir::lowering::condition_pattern::{ + analyze_condition_pattern, normalize_comparison, ConditionPattern + }; + + // (a) Pattern check: must be SimpleComparison + let pattern = analyze_condition_pattern(condition); + if pattern != ConditionPattern::SimpleComparison { // Complex condition → legacy mode (PoC lowering) return false; } + + // (b) Normalization check: must be normalizable + if normalize_comparison(condition).is_none() { + // Normalization failed → legacy mode + return false; + } } // Phase 219: Use assignment-based carrier detection 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 4ece3956..72e0af41 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 @@ -352,27 +352,49 @@ fn extract_loop_condition( where F: FnMut() -> ValueId, { - match cond { - ASTNode::BinaryOp { operator, left, right, .. } => { - let var_name = extract_variable_name(left)?; + // Phase 222: Normalize condition to canonical form (var on left) + use crate::mir::join_ir::lowering::condition_pattern::{normalize_comparison, ConditionValue}; - // 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 norm = normalize_comparison(cond) + .ok_or_else(|| "[if-sum] Condition normalization failed".to_string())?; - let op = match operator { - crate::ast::BinaryOperator::Less => CompareOp::Lt, - crate::ast::BinaryOperator::LessEqual => CompareOp::Le, - crate::ast::BinaryOperator::Greater => CompareOp::Gt, - crate::ast::BinaryOperator::GreaterEqual => CompareOp::Ge, - _ => return Err(format!("[if-sum] Unsupported loop condition operator: {:?}", operator)), - }; + // Extract normalized variable name and operator + let var_name = norm.left_var; - Ok((var_name, op, limit_value, limit_instructions)) + // Convert mir::CompareOp to join_ir::CompareOp + let op = match norm.op { + crate::mir::CompareOp::Lt => CompareOp::Lt, + crate::mir::CompareOp::Gt => CompareOp::Gt, + crate::mir::CompareOp::Le => CompareOp::Le, + crate::mir::CompareOp::Ge => CompareOp::Ge, + crate::mir::CompareOp::Eq => CompareOp::Eq, + crate::mir::CompareOp::Ne => CompareOp::Ne, + }; + + // Lower the right-hand side using condition_lowerer + // This handles both literals and variables via ConditionEnv + let mut limit_instructions = Vec::new(); + let limit_value = match norm.right { + ConditionValue::Literal(lit) => { + // Create Const instruction for literal + let val_id = alloc_value(); + limit_instructions.push(JoinInst::Compute(MirLikeInst::Const { + dst: val_id, + value: ConstValue::Integer(lit), + })); + val_id } - _ => Err("[if-sum] Loop condition must be a binary comparison".to_string()), - } + ConditionValue::Variable(var_name) => { + // Create Variable node and lower it via condition_lowerer + let var_node = ASTNode::Variable { + name: var_name, + span: crate::ast::Span { start: 0, end: 0, line: 1, column: 1 }, + }; + lower_value_expression(&var_node, alloc_value, cond_env, &mut limit_instructions)? + } + }; + + Ok((var_name, op, limit_value, limit_instructions)) } /// Extract if condition: variable, operator, and value