refactor(joinir): Pattern 3 ExitMeta化 - Hardcoded ValueIds削除
Refactoring 5.1: Pattern 3 を Pattern 4 と同じ ExitMeta ベースアーキテクチャに統一化
Changes:
1. loop_with_if_phi_minimal.rs
- 署名: Option<JoinModule> → Result<(JoinModule, JoinFragmentMeta), String>
- ExitMeta 動的生成ロジック追加(sum, count)
- インポート追加: carrier_info::{ExitMeta, JoinFragmentMeta}
2. pattern3_with_if_phi.rs
- Hardcoded 定数削除(PATTERN3_K_EXIT_*_ID 2個削除)
- Manual exit binding 42行 → ExitMetaCollector 4行に置き換え
- インポート追加: ExitMetaCollector
3. loop_patterns/with_if_phi.rs
- Result型変更に対応(.ok()? で変換)
Benefits:
- Pattern 3/4 アーキテクチャ統一化 ✅
- 19行純削減(+55 -74行、3ファイル合計) ✅
- Hardcoded ValueIds 完全撤廃 ✅
- Phase 213 AST-based generalization の基盤強化 ✅
Tests: All tests passing, loop_if_phi.hako outputs "sum=9" correctly
This commit is contained in:
@ -3,31 +3,11 @@
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::ValueId;
|
||||
use super::super::merge::exit_line::meta_collector::ExitMetaCollector;
|
||||
use super::super::trace;
|
||||
|
||||
/// Phase 179-A / Phase 195: Expected ValueIds for k_exit parameters in Pattern 3
|
||||
/// These correspond to the exit PHI inputs in the JoinIR lowering for loop_with_if_phi_minimal
|
||||
///
|
||||
/// # TODO (Phase 179 Task 2): Convert to ExitMeta-based exit binding generation
|
||||
///
|
||||
/// **Current State**: Hardcoded ValueIds - fragile and non-reusable
|
||||
///
|
||||
/// **Why it's hardcoded**:
|
||||
/// - Pattern 3's lowerer (`lower_loop_with_if_phi_pattern`) returns `Option<JoinModule>`
|
||||
/// - Unlike Pattern 4 which returns `(JoinModule, JoinFragmentMeta)`
|
||||
/// - No ExitMeta available to dynamically look up exit PHI ValueIds
|
||||
///
|
||||
/// **Migration Path** (when Pattern 3 lowerer is updated):
|
||||
/// 1. Change `lower_loop_with_if_phi_pattern` to return `(JoinModule, JoinFragmentMeta)`
|
||||
/// 2. Remove these constants
|
||||
/// 3. Use ExitMeta loop (like Pattern 4 lines 350-378) to generate exit_bindings dynamically
|
||||
/// 4. See: pattern4_with_continue.rs lines 350-378 for reference implementation
|
||||
///
|
||||
/// **Impact**: Low priority - Pattern 3 is test-only and works correctly with hardcoded values
|
||||
///
|
||||
/// Phase 195: Multi-carrier support - now includes both sum_final and count_final
|
||||
const PATTERN3_K_EXIT_SUM_FINAL_ID: ValueId = ValueId(24); // Phase 195: Updated from ValueId(18)
|
||||
const PATTERN3_K_EXIT_COUNT_FINAL_ID: ValueId = ValueId(25); // Phase 195: New count carrier
|
||||
// Phase 213: Hardcoded ValueIds removed - now using ExitMeta-based exit binding generation
|
||||
// See: ExitMetaCollector usage below (lines 115-135)
|
||||
|
||||
/// Phase 194: Detection function for Pattern 3
|
||||
///
|
||||
@ -106,62 +86,53 @@ impl MirBuilder {
|
||||
let mut join_value_space = JoinValueSpace::new();
|
||||
|
||||
// Call Pattern 3 lowerer with preprocessed scope
|
||||
let join_module = match lower_loop_with_if_phi_pattern(ctx.loop_scope, &mut join_value_space) {
|
||||
Some(module) => module,
|
||||
None => {
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern3", "Pattern 3 lowerer returned None");
|
||||
return Ok(None);
|
||||
let (join_module, fragment_meta) = match lower_loop_with_if_phi_pattern(ctx.loop_scope, &mut join_value_space) {
|
||||
Ok(result) => result,
|
||||
Err(e) => {
|
||||
trace::trace().debug("pattern3", &format!("Pattern 3 lowerer failed: {}", e));
|
||||
return Err(format!("[cf_loop/pattern3] Lowering failed: {}", e));
|
||||
}
|
||||
};
|
||||
|
||||
let exit_meta = &fragment_meta.exit_meta;
|
||||
|
||||
trace::trace().debug(
|
||||
"pattern3",
|
||||
&format!("ExitMeta: {} exit values", exit_meta.exit_values.len())
|
||||
);
|
||||
for (carrier_name, join_value) in &exit_meta.exit_values {
|
||||
trace::trace().debug(
|
||||
"pattern3",
|
||||
&format!(" {} → ValueId({})", carrier_name, join_value.0)
|
||||
);
|
||||
}
|
||||
|
||||
// Phase 195: Create boundary from context (multi-carrier support with backward compatibility)
|
||||
// Phase 201: Use JoinInlineBoundaryBuilder for clean construction
|
||||
// Canonical Builder pattern - see docs/development/current/main/joinir-boundary-builder-pattern.md
|
||||
self.trace_varmap("pattern3_before_merge");
|
||||
use crate::mir::join_ir::lowering::JoinInlineBoundaryBuilder;
|
||||
use crate::mir::join_ir::lowering::inline_boundary::LoopExitBinding;
|
||||
|
||||
// Phase 195: Build inputs and exit_bindings dynamically based on available carriers
|
||||
let (join_inputs, host_inputs, exit_bindings) = if has_count {
|
||||
// Multi-carrier: i, sum, count
|
||||
let count_var_id = count_carrier_opt.unwrap().host_id;
|
||||
(
|
||||
vec![ValueId(0), ValueId(1), ValueId(2)], // JoinIR's main() parameters
|
||||
vec![ctx.loop_var_id, sum_var_id, count_var_id], // Host's loop variables
|
||||
vec![
|
||||
LoopExitBinding {
|
||||
carrier_name: "sum".to_string(),
|
||||
join_exit_value: PATTERN3_K_EXIT_SUM_FINAL_ID, // ValueId(24)
|
||||
host_slot: sum_var_id,
|
||||
},
|
||||
LoopExitBinding {
|
||||
carrier_name: "count".to_string(),
|
||||
join_exit_value: PATTERN3_K_EXIT_COUNT_FINAL_ID, // ValueId(25)
|
||||
host_slot: count_var_id,
|
||||
}
|
||||
]
|
||||
)
|
||||
// Phase 213: Use ExitMetaCollector for dynamic exit binding generation
|
||||
// Note: ExitMetaCollector internally validates that all exit carriers in ExitMeta
|
||||
// have corresponding variable_map entries. No additional validation needed here.
|
||||
let exit_bindings = ExitMetaCollector::collect(
|
||||
self,
|
||||
exit_meta,
|
||||
debug,
|
||||
);
|
||||
|
||||
// Build join_inputs and host_inputs (retain existing logic)
|
||||
let join_inputs = vec![ValueId(0), ValueId(1), ValueId(2)];
|
||||
let mut host_inputs = vec![ctx.loop_var_id, sum_var_id];
|
||||
|
||||
if has_count {
|
||||
host_inputs.push(count_carrier_opt.unwrap().host_id);
|
||||
} else {
|
||||
// Single-carrier (backward compatibility): i, sum only
|
||||
// Phase 195: JoinIR lowerer now always generates 3 parameters (i, sum, count)
|
||||
// For backward compat, we create a dummy count variable that will be discarded
|
||||
use crate::mir::builder::emission::constant;
|
||||
let dummy_count_id = constant::emit_void(self); // Use void as dummy value
|
||||
|
||||
(
|
||||
vec![ValueId(0), ValueId(1), ValueId(2)], // JoinIR's main() parameters (i, sum, count)
|
||||
vec![ctx.loop_var_id, sum_var_id, dummy_count_id], // Host's loop variables (count is dummy)
|
||||
vec![
|
||||
LoopExitBinding {
|
||||
carrier_name: "sum".to_string(),
|
||||
join_exit_value: PATTERN3_K_EXIT_SUM_FINAL_ID, // ValueId(24)
|
||||
host_slot: sum_var_id,
|
||||
}
|
||||
// Don't bind count in single-carrier mode - it's just discarded
|
||||
]
|
||||
)
|
||||
};
|
||||
let dummy_count_id = constant::emit_void(self);
|
||||
host_inputs.push(dummy_count_id);
|
||||
}
|
||||
|
||||
let boundary = JoinInlineBoundaryBuilder::new()
|
||||
.with_inputs(join_inputs, host_inputs)
|
||||
|
||||
Reference in New Issue
Block a user