feat(joinir): emit balanced depth-scan derived vars
This commit is contained in:
@ -52,6 +52,7 @@ impl EmitJoinIRStepBox {
|
||||
skeleton,
|
||||
condition_only_recipe: inputs.condition_only_recipe.as_ref(),
|
||||
body_local_derived_recipe: inputs.body_local_derived_recipe.as_ref(),
|
||||
balanced_depth_scan_recipe: inputs.balanced_depth_scan_recipe.as_ref(),
|
||||
};
|
||||
|
||||
let (join_module, fragment_meta) = match lower_loop_with_break_minimal(lowering_inputs) {
|
||||
|
||||
@ -5,6 +5,11 @@
|
||||
//! - `depth_delta`: per-iteration delta (-1/0/+1)
|
||||
//! - `depth_next`: depth + depth_delta (for break checks)
|
||||
|
||||
use crate::mir::join_ir::lowering::condition_env::ConditionEnv;
|
||||
use crate::mir::join_ir::lowering::loop_body_local_env::LoopBodyLocalEnv;
|
||||
use crate::mir::join_ir::{BinOpKind, CompareOp, ConstValue, JoinInst, MirLikeInst};
|
||||
use crate::mir::ValueId;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BalancedDepthScanRecipe {
|
||||
pub depth_var: String,
|
||||
@ -15,3 +20,105 @@ pub struct BalancedDepthScanRecipe {
|
||||
pub depth_next_name: String,
|
||||
}
|
||||
|
||||
pub struct BalancedDepthScanEmitter;
|
||||
|
||||
impl BalancedDepthScanEmitter {
|
||||
pub fn emit_derived(
|
||||
recipe: &BalancedDepthScanRecipe,
|
||||
body_local_env: &mut LoopBodyLocalEnv,
|
||||
condition_env: &ConditionEnv,
|
||||
alloc_value: &mut dyn FnMut() -> ValueId,
|
||||
instructions: &mut Vec<JoinInst>,
|
||||
) -> Result<(), String> {
|
||||
let ch_id = body_local_env.get(&recipe.ch_var).ok_or_else(|| {
|
||||
format!(
|
||||
"[phase107/balanced-depth] ch '{}' not found in LoopBodyLocalEnv",
|
||||
recipe.ch_var
|
||||
)
|
||||
})?;
|
||||
let depth_id = condition_env.get(&recipe.depth_var).ok_or_else(|| {
|
||||
format!(
|
||||
"[phase107/balanced-depth] depth '{}' not found in ConditionEnv",
|
||||
recipe.depth_var
|
||||
)
|
||||
})?;
|
||||
|
||||
let const_open = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: const_open,
|
||||
value: ConstValue::String(recipe.open.clone()),
|
||||
}));
|
||||
let const_close = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: const_close,
|
||||
value: ConstValue::String(recipe.close.clone()),
|
||||
}));
|
||||
|
||||
let is_open = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||
dst: is_open,
|
||||
op: CompareOp::Eq,
|
||||
lhs: ch_id,
|
||||
rhs: const_open,
|
||||
}));
|
||||
let is_close = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||
dst: is_close,
|
||||
op: CompareOp::Eq,
|
||||
lhs: ch_id,
|
||||
rhs: const_close,
|
||||
}));
|
||||
|
||||
let const_1 = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: const_1,
|
||||
value: ConstValue::Integer(1),
|
||||
}));
|
||||
let const_0 = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: const_0,
|
||||
value: ConstValue::Integer(0),
|
||||
}));
|
||||
let const_m1 = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: const_m1,
|
||||
value: ConstValue::Integer(-1),
|
||||
}));
|
||||
|
||||
let delta_open = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Select {
|
||||
dst: delta_open,
|
||||
cond: is_open,
|
||||
then_val: const_1,
|
||||
else_val: const_0,
|
||||
}));
|
||||
|
||||
let delta_close = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Select {
|
||||
dst: delta_close,
|
||||
cond: is_close,
|
||||
then_val: const_m1,
|
||||
else_val: const_0,
|
||||
}));
|
||||
|
||||
let depth_delta = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||
dst: depth_delta,
|
||||
op: BinOpKind::Add,
|
||||
lhs: delta_open,
|
||||
rhs: delta_close,
|
||||
}));
|
||||
|
||||
let depth_next = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||
dst: depth_next,
|
||||
op: BinOpKind::Add,
|
||||
lhs: depth_id,
|
||||
rhs: depth_delta,
|
||||
}));
|
||||
|
||||
body_local_env.insert(recipe.depth_delta_name.clone(), depth_delta);
|
||||
body_local_env.insert(recipe.depth_next_name.clone(), depth_next);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,6 +68,7 @@ use crate::mir::join_ir::lowering::carrier_update_emitter::{
|
||||
// Phase 92 P2-1: Import ConditionalStep emitter from dedicated module
|
||||
use crate::mir::join_ir::lowering::common::conditional_step_emitter::emit_conditional_step_update;
|
||||
use crate::mir::join_ir::lowering::common::body_local_derived_emitter::BodyLocalDerivedRecipe;
|
||||
use crate::mir::join_ir::lowering::common::balanced_depth_scan_emitter::{BalancedDepthScanEmitter, BalancedDepthScanRecipe};
|
||||
use crate::mir::join_ir::lowering::condition_to_joinir::ConditionEnv;
|
||||
use crate::mir::loop_canonicalizer::UpdateKind;
|
||||
use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
|
||||
@ -111,6 +112,8 @@ pub(crate) struct LoopWithBreakLoweringInputs<'a> {
|
||||
pub condition_only_recipe: Option<&'a crate::mir::join_ir::lowering::common::condition_only_emitter::ConditionOnlyRecipe>,
|
||||
/// Phase 94: BodyLocalDerived recipe (P5b escape `ch` reassignment + conditional counter).
|
||||
pub body_local_derived_recipe: Option<&'a BodyLocalDerivedRecipe>,
|
||||
/// Phase 107: Balanced depth-scan recipe (find_balanced_* family).
|
||||
pub balanced_depth_scan_recipe: Option<&'a BalancedDepthScanRecipe>,
|
||||
}
|
||||
|
||||
/// Lower Pattern 2 (Loop with Conditional Break) to JoinIR
|
||||
@ -189,6 +192,7 @@ pub(crate) fn lower_loop_with_break_minimal(
|
||||
skeleton,
|
||||
condition_only_recipe,
|
||||
body_local_derived_recipe,
|
||||
balanced_depth_scan_recipe,
|
||||
} = inputs;
|
||||
|
||||
let mut body_local_env = body_local_env;
|
||||
@ -492,6 +496,17 @@ pub(crate) fn lower_loop_with_break_minimal(
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
// Phase 107: Balanced depth-scan derived vars (depth_delta/depth_next)
|
||||
if let Some(recipe) = balanced_depth_scan_recipe {
|
||||
BalancedDepthScanEmitter::emit_derived(
|
||||
recipe,
|
||||
body_env,
|
||||
env,
|
||||
&mut alloc_value,
|
||||
&mut body_init_block,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@ -148,6 +148,7 @@ fn test_pattern2_header_condition_via_exprlowerer() {
|
||||
skeleton: None, // Phase 92 P0-3: skeleton=None for backward compatibility
|
||||
condition_only_recipe: None, // Phase 93 P0: None for normal loops
|
||||
body_local_derived_recipe: None, // Phase 94: None for normal loops
|
||||
balanced_depth_scan_recipe: None, // Phase 107: None for normal loops
|
||||
});
|
||||
|
||||
assert!(result.is_ok(), "ExprLowerer header path should succeed");
|
||||
|
||||
@ -137,6 +137,7 @@ pub fn build_pattern2_minimal_structured() -> JoinModule {
|
||||
skeleton: None, // Phase 92 P0-3: skeleton=None for backward compatibility
|
||||
condition_only_recipe: None, // Phase 93 P0: None for normal loops
|
||||
body_local_derived_recipe: None, // Phase 94: None for fixture
|
||||
balanced_depth_scan_recipe: None, // Phase 107: None for fixture
|
||||
},
|
||||
)
|
||||
.expect("pattern2 minimal lowering should succeed");
|
||||
|
||||
Reference in New Issue
Block a user