refactor(joinir): Pattern 4 modularization with CarrierInfo/ExitMeta
Removes hardcoded "sum" and ValueId(15) from Pattern 4 lowerer by introducing CarrierInfo and ExitMeta structures. Changes: - New carrier_info.rs: CarrierInfo, CarrierVar, ExitMeta structs - loop_with_continue_minimal.rs: Returns (JoinModule, ExitMeta) - pattern4_with_continue.rs: Dynamic binding generation from metadata Design approach: "Thin meta on existing boxes" (ChatGPT proposal) - CarrierInfo: Built from variable_map, not AST re-analysis - ExitMeta: Carrier name + JoinIR ValueId pairs from lowerer - LoopExitBinding: Auto-generated from CarrierInfo + ExitMeta Test: loop_continue_pattern4.hako outputs 25 (unchanged) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
64
src/mir/join_ir/lowering/carrier_info.rs
Normal file
64
src/mir/join_ir/lowering/carrier_info.rs
Normal file
@ -0,0 +1,64 @@
|
||||
//! Carrier variable metadata for JoinIR loop lowering
|
||||
//!
|
||||
//! This module defines metadata structures for tracking carrier variables
|
||||
//! in loop lowering. This enables dynamic generation of exit bindings
|
||||
//! without hardcoded variable names or ValueIds.
|
||||
|
||||
use crate::mir::ValueId;
|
||||
|
||||
/// Information about a single carrier variable
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CarrierVar {
|
||||
/// Variable name (e.g., "sum", "printed")
|
||||
pub name: String,
|
||||
/// Host ValueId for this variable
|
||||
pub host_id: ValueId,
|
||||
}
|
||||
|
||||
/// Complete carrier information for a loop
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CarrierInfo {
|
||||
/// Loop control variable name (e.g., "i")
|
||||
pub loop_var_name: String,
|
||||
/// Loop control variable ValueId in host
|
||||
pub loop_var_id: ValueId,
|
||||
/// Additional carrier variables (e.g., sum, printed)
|
||||
pub carriers: Vec<CarrierVar>,
|
||||
}
|
||||
|
||||
/// Exit metadata returned by lowerers
|
||||
///
|
||||
/// This structure captures the mapping from JoinIR exit values to
|
||||
/// carrier variable names, enabling dynamic binding generation.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExitMeta {
|
||||
/// Exit value bindings: (carrier_name, join_exit_value_id)
|
||||
///
|
||||
/// Example for Pattern 4:
|
||||
/// ```
|
||||
/// vec![("sum".to_string(), ValueId(15))]
|
||||
/// ```
|
||||
/// where ValueId(15) is the k_exit parameter in JoinIR-local space.
|
||||
pub exit_values: Vec<(String, ValueId)>,
|
||||
}
|
||||
|
||||
impl ExitMeta {
|
||||
/// Create new ExitMeta with no exit values
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
exit_values: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// Create ExitMeta with a single exit value
|
||||
pub fn single(carrier_name: String, join_value: ValueId) -> Self {
|
||||
Self {
|
||||
exit_values: vec![(carrier_name, join_value)],
|
||||
}
|
||||
}
|
||||
|
||||
/// Create ExitMeta with multiple exit values
|
||||
pub fn multiple(exit_values: Vec<(String, ValueId)>) -> Self {
|
||||
Self { exit_values }
|
||||
}
|
||||
}
|
||||
@ -68,6 +68,7 @@
|
||||
//!
|
||||
//! Following the "80/20 rule" from CLAUDE.md - get it working first, generalize later.
|
||||
|
||||
use crate::mir::join_ir::lowering::carrier_info::ExitMeta;
|
||||
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
||||
use crate::mir::join_ir::{
|
||||
BinOpKind, CompareOp, ConstValue, JoinFuncId, JoinFunction, JoinInst, JoinModule,
|
||||
@ -101,7 +102,7 @@ use crate::mir::ValueId;
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Some(JoinModule)` - Successfully lowered to JoinIR
|
||||
/// * `Some((JoinModule, ExitMeta))` - Successfully lowered to JoinIR with exit metadata
|
||||
/// * `None` - Pattern not matched (fallback to other lowerers)
|
||||
///
|
||||
/// # Boundary Contract
|
||||
@ -109,8 +110,9 @@ use crate::mir::ValueId;
|
||||
/// This function returns a JoinModule with:
|
||||
/// - **Input slots**: ValueId(0) = i_init, ValueId(1) = sum_init
|
||||
/// - **Output slot**: k_exit returns the final sum value
|
||||
/// - **Exit metadata**: ExitMeta containing ("sum", ValueId(15)) binding
|
||||
/// - **Caller responsibility**: Create JoinInlineBoundary to map ValueIds
|
||||
pub fn lower_loop_with_continue_minimal(_scope: LoopScopeShape) -> Option<JoinModule> {
|
||||
pub fn lower_loop_with_continue_minimal(_scope: LoopScopeShape) -> Option<(JoinModule, ExitMeta)> {
|
||||
// Phase 195: Use local ValueId allocator (sequential from 0)
|
||||
// JoinIR has NO knowledge of host ValueIds - boundary handled separately
|
||||
let mut value_counter = 0u32;
|
||||
@ -345,5 +347,11 @@ pub fn lower_loop_with_continue_minimal(_scope: LoopScopeShape) -> Option<JoinMo
|
||||
eprintln!("[joinir/pattern4] Continue: Jump(loop_step) to skip iteration");
|
||||
eprintln!("[joinir/pattern4] Carriers: i, sum");
|
||||
|
||||
Some(join_module)
|
||||
// Phase 196: Return ExitMeta with carrier bindings
|
||||
// k_exit parameter sum_exit (ValueId(15)) should be bound to host's "sum" variable
|
||||
let exit_meta = ExitMeta::single("sum".to_string(), sum_exit);
|
||||
|
||||
eprintln!("[joinir/pattern4] ExitMeta: sum → ValueId({})", sum_exit.0);
|
||||
|
||||
Some((join_module, exit_meta))
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
//! - `if_select.rs`: Phase 33 If/Else → Select lowering
|
||||
//! - `if_dry_runner.rs`: Phase 33-10 If lowering dry-run スキャナー(箱化版)
|
||||
|
||||
pub mod carrier_info; // Phase 196: Carrier metadata for loop lowering
|
||||
pub mod common;
|
||||
pub mod exit_args_resolver;
|
||||
pub mod funcscanner_append_defs;
|
||||
|
||||
Reference in New Issue
Block a user