feat(joinir): Phase 47-A-LOWERING - P3 Normalized→MIR(direct)
Implement full Pattern3 (if-sum) Normalized→MIR(direct) support, completing
the P3 minimal implementation.
Key changes:
1. P3 Shape Detection (shape_guard.rs):
- Implemented is_pattern3_if_sum_minimal() with structure-based detection
- Detects P3 characteristics:
- Has Compare instruction (loop condition)
- Has Select instruction (conditional carrier update)
- Has tail call (Call with k_next: None)
- Reasonable param count (2-4 for i, sum carriers)
- Handles both JoinInst::Select and Compute(MirLikeInst::Select)
- Added unit test: test_detect_pattern3_if_sum_minimal_shape ✅
2. P3 Normalization Function (normalized.rs):
- Implemented normalize_pattern3_if_sum_minimal()
- Guards: Validates Structured JoinIR + P3 shape detection
- Phase 47-A minimal: Delegates to P2 normalization (works for simple cases)
- Updated normalized_dev_roundtrip_structured() integration
- Returns Result<NormalizedModule, String> for proper error handling
3. Bridge Integration (bridge.rs):
- Updated normalize_for_shape() to call P3 normalization
- No changes needed to direct.rs (already handles P3 instructions)
4. Integration Tests (normalized_joinir_min.rs):
- Added test_phase47a_pattern3_if_sum_minimal_normalization
- Tests Structured→Normalized transformation
- Verifies shape detection + normalization succeeds
- Validates function count and phase correctness
- Added test_phase47a_pattern3_if_sum_minimal_runner
- Basic smoke test for P3 fixture validity
- Verifies 3-function structure and entry point
Benefits:
- P3 now uses Normalized→MIR(direct) pipeline (same as P1/P2)
- Structure-based detection (no name-based heuristics)
- Minimal implementation (delegates to P2 for simplicity)
- Pure additive (no P1/P2 behavioral changes)
Tests: 938/938 PASS (lib), shape_guard P3 test PASS
- test_detect_pattern3_if_sum_minimal_shape ✅
- test_phase47a_pattern3_if_sum_minimal_normalization ✅
- test_phase47a_pattern3_if_sum_minimal_runner ✅
Next phase: Phase 47-B (proper P3-specific normalization, array_filter, multi-carrier)
Design note: This minimal implementation reuses P2 normalization for simplicity.
Proper P3-specific normalization (IfCond, ThenUpdates, ElseUpdates step sequence)
will be implemented in Phase 47-B when needed for more complex P3 patterns.
This commit is contained in:
@ -349,14 +349,50 @@ mod detectors {
|
||||
|
||||
/// Phase 47-A: Check if module matches Pattern3 if-sum minimal shape
|
||||
pub(crate) fn is_pattern3_if_sum_minimal(module: &JoinModule) -> bool {
|
||||
// For now, simple heuristic:
|
||||
// - Has Pattern3 structure (if-sum)
|
||||
// - Single carrier (sum)
|
||||
// - Simple loop condition
|
||||
// Structure-based detection (avoid name-based heuristics)
|
||||
|
||||
// TODO: Implement proper detection based on fixture
|
||||
// For Phase 47-A, this will be called explicitly in tests
|
||||
false // Placeholder - will be refined in later commits
|
||||
// Must have exactly 3 functions: main, loop_step, k_exit
|
||||
if !module.is_structured() || module.functions.len() != 3 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find loop_step function
|
||||
let loop_step = match find_loop_step(module) {
|
||||
Some(f) => f,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// P3 characteristics:
|
||||
// - Has Compare instruction (loop condition)
|
||||
// - Has Select instruction (conditional carrier update: if-then-else)
|
||||
// - Has tail call (Call with k_next: None)
|
||||
|
||||
let has_compare = loop_step.body.iter().any(|inst| {
|
||||
matches!(
|
||||
inst,
|
||||
JoinInst::Compute(crate::mir::join_ir::MirLikeInst::Compare { .. })
|
||||
)
|
||||
});
|
||||
|
||||
// Phase 220: Select can be either JoinInst::Select or Compute(MirLikeInst::Select)
|
||||
let has_select = loop_step.body.iter().any(|inst| match inst {
|
||||
JoinInst::Select { .. } => true,
|
||||
JoinInst::Compute(mir_inst) => matches!(
|
||||
mir_inst,
|
||||
crate::mir::join_ir::MirLikeInst::Select { .. }
|
||||
),
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let has_tail_call = loop_step
|
||||
.body
|
||||
.iter()
|
||||
.any(|inst| matches!(inst, JoinInst::Call { k_next: None, .. }));
|
||||
|
||||
// P3 minimal has 2-4 params (i, sum, possibly n)
|
||||
let reasonable_param_count = (2..=4).contains(&loop_step.params.len());
|
||||
|
||||
has_compare && has_select && has_tail_call && reasonable_param_count
|
||||
}
|
||||
|
||||
pub(super) fn find_loop_step(module: &JoinModule) -> Option<&JoinFunction> {
|
||||
@ -376,3 +412,29 @@ fn log_shapes(tag: &str, shapes: &[NormalizedDevShape]) {
|
||||
eprintln!("[joinir/normalized-dev/shape] {}: {:?}", tag, shapes);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
#[test]
|
||||
fn test_detect_pattern3_if_sum_minimal_shape() {
|
||||
use crate::mir::join_ir::normalized::fixtures::build_pattern3_if_sum_min_structured_for_normalized_dev;
|
||||
|
||||
let module = build_pattern3_if_sum_min_structured_for_normalized_dev();
|
||||
|
||||
// Should detect Pattern3IfSumMinimal shape
|
||||
assert!(
|
||||
detectors::is_pattern3_if_sum_minimal(&module),
|
||||
"pattern3_if_sum_minimal fixture should be detected"
|
||||
);
|
||||
|
||||
let shapes = detect_shapes(&module);
|
||||
assert!(
|
||||
shapes.contains(&NormalizedDevShape::Pattern3IfSumMinimal),
|
||||
"detect_shapes() should include Pattern3IfSumMinimal, got: {:?}",
|
||||
shapes
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user