feat(joinir): emit balanced depth-scan derived vars

This commit is contained in:
nyash-codex
2025-12-17 22:32:50 +09:00
parent bf80789757
commit aa29dc8085
5 changed files with 125 additions and 0 deletions

View File

@ -52,6 +52,7 @@ impl EmitJoinIRStepBox {
skeleton, skeleton,
condition_only_recipe: inputs.condition_only_recipe.as_ref(), condition_only_recipe: inputs.condition_only_recipe.as_ref(),
body_local_derived_recipe: inputs.body_local_derived_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) { let (join_module, fragment_meta) = match lower_loop_with_break_minimal(lowering_inputs) {

View File

@ -5,6 +5,11 @@
//! - `depth_delta`: per-iteration delta (-1/0/+1) //! - `depth_delta`: per-iteration delta (-1/0/+1)
//! - `depth_next`: depth + depth_delta (for break checks) //! - `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)] #[derive(Debug, Clone)]
pub struct BalancedDepthScanRecipe { pub struct BalancedDepthScanRecipe {
pub depth_var: String, pub depth_var: String,
@ -15,3 +20,105 @@ pub struct BalancedDepthScanRecipe {
pub depth_next_name: String, 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(())
}
}

View File

@ -68,6 +68,7 @@ use crate::mir::join_ir::lowering::carrier_update_emitter::{
// Phase 92 P2-1: Import ConditionalStep emitter from dedicated module // 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::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::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::join_ir::lowering::condition_to_joinir::ConditionEnv;
use crate::mir::loop_canonicalizer::UpdateKind; use crate::mir::loop_canonicalizer::UpdateKind;
use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace; 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>, 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). /// Phase 94: BodyLocalDerived recipe (P5b escape `ch` reassignment + conditional counter).
pub body_local_derived_recipe: Option<&'a BodyLocalDerivedRecipe>, 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 /// Lower Pattern 2 (Loop with Conditional Break) to JoinIR
@ -189,6 +192,7 @@ pub(crate) fn lower_loop_with_break_minimal(
skeleton, skeleton,
condition_only_recipe, condition_only_recipe,
body_local_derived_recipe, body_local_derived_recipe,
balanced_depth_scan_recipe,
} = inputs; } = inputs;
let mut body_local_env = body_local_env; 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,
)?;
}
} }
// ------------------------------------------------------------------ // ------------------------------------------------------------------

View File

@ -148,6 +148,7 @@ fn test_pattern2_header_condition_via_exprlowerer() {
skeleton: None, // Phase 92 P0-3: skeleton=None for backward compatibility skeleton: None, // Phase 92 P0-3: skeleton=None for backward compatibility
condition_only_recipe: None, // Phase 93 P0: None for normal loops condition_only_recipe: None, // Phase 93 P0: None for normal loops
body_local_derived_recipe: None, // Phase 94: 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"); assert!(result.is_ok(), "ExprLowerer header path should succeed");

View File

@ -137,6 +137,7 @@ pub fn build_pattern2_minimal_structured() -> JoinModule {
skeleton: None, // Phase 92 P0-3: skeleton=None for backward compatibility skeleton: None, // Phase 92 P0-3: skeleton=None for backward compatibility
condition_only_recipe: None, // Phase 93 P0: None for normal loops condition_only_recipe: None, // Phase 93 P0: None for normal loops
body_local_derived_recipe: None, // Phase 94: None for fixture 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"); .expect("pattern2 minimal lowering should succeed");