fix(joinir): Phase 118 Pattern3 exit carrier PHI SSOT
This commit is contained in:
@ -1,9 +1,48 @@
|
|||||||
use super::LoopHeaderPhiInfo;
|
|
||||||
use crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary;
|
use crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary;
|
||||||
|
use crate::mir::ValueId;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
use super::LoopHeaderPhiInfo;
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
use crate::mir::join_ir::lowering::join_value_space::{LOCAL_MAX, PARAM_MAX, PARAM_MIN};
|
use crate::mir::join_ir::lowering::join_value_space::{LOCAL_MAX, PARAM_MAX, PARAM_MIN};
|
||||||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
#[cfg(debug_assertions)]
|
||||||
|
use crate::mir::{BasicBlockId, MirFunction, MirInstruction};
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// Phase 118 P2: Contract check (Fail-Fast) - exit_bindings carriers must have exit PHI dsts.
|
||||||
|
///
|
||||||
|
/// This prevents latent "Carrier '<name>' not found in carrier_phis" failures later in
|
||||||
|
/// ExprResultResolver and ExitLine reconnection.
|
||||||
|
pub(super) fn verify_exit_bindings_have_exit_phis(
|
||||||
|
boundary: &JoinInlineBoundary,
|
||||||
|
exit_carrier_phis: &BTreeMap<String, ValueId>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
|
||||||
|
use crate::mir::join_ir::lowering::error_tags;
|
||||||
|
|
||||||
|
for binding in &boundary.exit_bindings {
|
||||||
|
if binding.role == CarrierRole::ConditionOnly {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if exit_carrier_phis.contains_key(&binding.carrier_name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(error_tags::freeze_with_hint(
|
||||||
|
"phase118/exit_phi/missing_carrier_phi",
|
||||||
|
&format!(
|
||||||
|
"exit_bindings carrier '{}' is missing from exit_carrier_phis",
|
||||||
|
binding.carrier_name
|
||||||
|
),
|
||||||
|
"exit_bindings carriers must be included in exit_phi_builder inputs; check carrier_inputs derivation from jump_args",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
pub(super) fn verify_loop_header_phis(
|
pub(super) fn verify_loop_header_phis(
|
||||||
func: &MirFunction,
|
func: &MirFunction,
|
||||||
|
|||||||
@ -650,12 +650,46 @@ pub(super) fn merge_and_rewrite(
|
|||||||
|
|
||||||
// Phase 246-EX: Collect exit values from jump_args
|
// Phase 246-EX: Collect exit values from jump_args
|
||||||
if let Some(b) = boundary {
|
if let Some(b) = boundary {
|
||||||
if let Some(ref carrier_info) = b.carrier_info {
|
// ExprResult collection: first jump arg is preserved as Return value by the converter,
|
||||||
let expected_args = carrier_info.carriers.len() + 1; // loop_var + carriers
|
// and is the SSOT for exit_phi_inputs in this merge phase.
|
||||||
if remapped_args.len() < expected_args {
|
if let Some(&first_exit) = remapped_args.first() {
|
||||||
|
exit_phi_inputs.push((new_block_id, first_exit));
|
||||||
|
log!(
|
||||||
|
verbose,
|
||||||
|
"[DEBUG-177] Phase 246-EX: exit_phi_inputs from jump_args[0]: ({:?}, {:?})",
|
||||||
|
new_block_id, first_exit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 118 P2: carrier_inputs SSOT = boundary.exit_bindings
|
||||||
|
//
|
||||||
|
// Contract:
|
||||||
|
// - Every LoopState carrier in exit_bindings must have an exit PHI input.
|
||||||
|
// - jump_args order is assumed to match exit_bindings order, with at most one
|
||||||
|
// leading extra slot (legacy layouts).
|
||||||
|
//
|
||||||
|
// This avoids Pattern3-specific assumptions such as "jump_args[0] is loop_var".
|
||||||
|
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
|
||||||
|
let exit_phi_bindings: Vec<_> = b
|
||||||
|
.exit_bindings
|
||||||
|
.iter()
|
||||||
|
.filter(|eb| eb.role != CarrierRole::ConditionOnly)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if !exit_phi_bindings.is_empty() {
|
||||||
|
let offset = if remapped_args.len()
|
||||||
|
== exit_phi_bindings.len()
|
||||||
|
{
|
||||||
|
0usize
|
||||||
|
} else if remapped_args.len()
|
||||||
|
== exit_phi_bindings.len() + 1
|
||||||
|
{
|
||||||
|
1usize
|
||||||
|
} else if remapped_args.len() < exit_phi_bindings.len()
|
||||||
|
{
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"[joinir/exit-line] jump_args length mismatch: expected at least {} (loop_var + carriers) but got {} in block {:?}",
|
"[joinir/exit-line] jump_args too short: need {} carrier args (from exit_bindings) but got {} in block {:?}",
|
||||||
expected_args,
|
exit_phi_bindings.len(),
|
||||||
remapped_args.len(),
|
remapped_args.len(),
|
||||||
old_block.id
|
old_block.id
|
||||||
);
|
);
|
||||||
@ -664,91 +698,56 @@ pub(super) fn merge_and_rewrite(
|
|||||||
} else {
|
} else {
|
||||||
log!(verbose, "[DEBUG-177] {}", msg);
|
log!(verbose, "[DEBUG-177] {}", msg);
|
||||||
}
|
}
|
||||||
}
|
0usize
|
||||||
}
|
} else {
|
||||||
|
let msg = format!(
|
||||||
// First arg is the loop variable (expr_result)
|
"[joinir/exit-line] jump_args length mismatch: expected {} or {} (exit_bindings carriers ±1) but got {} in block {:?}",
|
||||||
if let Some(&loop_var_exit) = remapped_args.first() {
|
exit_phi_bindings.len(),
|
||||||
exit_phi_inputs.push((new_block_id, loop_var_exit));
|
exit_phi_bindings.len() + 1,
|
||||||
log!(
|
remapped_args.len(),
|
||||||
verbose,
|
old_block.id
|
||||||
"[DEBUG-177] Phase 246-EX: exit_phi_inputs from jump_args[0]: ({:?}, {:?})",
|
|
||||||
new_block_id, loop_var_exit
|
|
||||||
);
|
|
||||||
|
|
||||||
// Phase 246-EX-P5: Also add loop_var to carrier_inputs if it's a named variable
|
|
||||||
// (Pattern 5 case: counter is both loop_var AND a carrier)
|
|
||||||
if let Some(ref loop_var_name) = b.loop_var_name {
|
|
||||||
carrier_inputs
|
|
||||||
.entry(loop_var_name.clone())
|
|
||||||
.or_insert_with(Vec::new)
|
|
||||||
.push((new_block_id, loop_var_exit));
|
|
||||||
log!(
|
|
||||||
verbose,
|
|
||||||
"[DEBUG-177] Phase 246-EX-P5: Added loop_var '{}' to carrier_inputs: ({:?}, {:?})",
|
|
||||||
loop_var_name, new_block_id, loop_var_exit
|
|
||||||
);
|
);
|
||||||
}
|
if strict_exit {
|
||||||
}
|
return Err(msg);
|
||||||
|
} else {
|
||||||
// Phase 246-EX-FIX: jump_args are in carrier_info.carriers order, not exit_bindings order!
|
log!(verbose, "[DEBUG-177] {}", msg);
|
||||||
//
|
|
||||||
// jump_args layout: [loop_var, carrier1, carrier2, ...]
|
|
||||||
// where carriers follow carrier_info.carriers order (NOT exit_bindings order)
|
|
||||||
//
|
|
||||||
// We need to:
|
|
||||||
// 1. Iterate through carrier_info.carriers (to get the right index)
|
|
||||||
// 2. Skip ConditionOnly carriers (they don't participate in exit PHI)
|
|
||||||
// 3. Map the jump_args index to the carrier name
|
|
||||||
if let Some(ref carrier_info) = b.carrier_info {
|
|
||||||
for (carrier_idx, carrier) in
|
|
||||||
carrier_info.carriers.iter().enumerate()
|
|
||||||
{
|
|
||||||
// Phase 227: Skip ConditionOnly carriers
|
|
||||||
if carrier.role == crate::mir::join_ir::lowering::carrier_info::CarrierRole::ConditionOnly {
|
|
||||||
log!(
|
|
||||||
verbose,
|
|
||||||
"[DEBUG-177] Phase 227: Skipping ConditionOnly carrier '{}' from exit PHI",
|
|
||||||
carrier.name
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
0usize
|
||||||
|
};
|
||||||
|
|
||||||
// jump_args[0] = loop_var, jump_args[1..] = carriers
|
for (binding_idx, binding) in
|
||||||
let jump_args_idx = carrier_idx + 1;
|
exit_phi_bindings.iter().enumerate()
|
||||||
|
{
|
||||||
|
let jump_args_idx = offset + binding_idx;
|
||||||
if let Some(&carrier_exit) =
|
if let Some(&carrier_exit) =
|
||||||
remapped_args.get(jump_args_idx)
|
remapped_args.get(jump_args_idx)
|
||||||
{
|
{
|
||||||
carrier_inputs
|
carrier_inputs
|
||||||
.entry(carrier.name.clone())
|
.entry(binding.carrier_name.clone())
|
||||||
.or_insert_with(Vec::new)
|
.or_insert_with(Vec::new)
|
||||||
.push((new_block_id, carrier_exit));
|
.push((new_block_id, carrier_exit));
|
||||||
log!(
|
log!(
|
||||||
verbose,
|
verbose,
|
||||||
"[DEBUG-177] Phase 246-EX-FIX: Collecting carrier '{}': from {:?} using jump_args[{}] = {:?}",
|
"[DEBUG-177] Phase 118: Collecting carrier '{}': from {:?} using jump_args[{}] = {:?}",
|
||||||
carrier.name, new_block_id, jump_args_idx, carrier_exit
|
binding.carrier_name,
|
||||||
|
new_block_id,
|
||||||
|
jump_args_idx,
|
||||||
|
carrier_exit
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"[joinir/exit-line] Missing jump_args entry for carrier '{}' at index {} in block {:?}",
|
"[joinir/exit-line] Missing jump_args entry for exit_binding carrier '{}' at index {} in block {:?}",
|
||||||
carrier.name, jump_args_idx, old_block.id
|
binding.carrier_name,
|
||||||
|
jump_args_idx,
|
||||||
|
old_block.id
|
||||||
);
|
);
|
||||||
if strict_exit {
|
if strict_exit {
|
||||||
return Err(msg);
|
return Err(msg);
|
||||||
} else {
|
} else {
|
||||||
log!(
|
log!(verbose, "[DEBUG-177] {}", msg);
|
||||||
verbose,
|
|
||||||
"[DEBUG-177] Phase 246-EX WARNING: No jump_args entry for carrier '{}' at index {}",
|
|
||||||
carrier.name, jump_args_idx
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log!(
|
|
||||||
verbose,
|
|
||||||
"[DEBUG-177] Phase 246-EX WARNING: No carrier_info in boundary!"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
mod block_allocator;
|
mod block_allocator;
|
||||||
mod carrier_init_builder;
|
mod carrier_init_builder;
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
mod contract_checks;
|
mod contract_checks;
|
||||||
pub mod exit_line;
|
pub mod exit_line;
|
||||||
mod exit_phi_builder;
|
mod exit_phi_builder;
|
||||||
@ -738,6 +737,48 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
|||||||
debug,
|
debug,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// Phase 118 P2: Contract check (Fail-Fast) - exit_bindings LoopState carriers must have exit PHIs.
|
||||||
|
if let Some(boundary) = boundary {
|
||||||
|
contract_checks::verify_exit_bindings_have_exit_phis(boundary, &exit_carrier_phis)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 118 P1: Dev-only carrier-phi SSOT logs (exit_bindings vs carrier_inputs vs exit_carrier_phis)
|
||||||
|
if crate::config::env::joinir_dev_enabled() {
|
||||||
|
if let Some(boundary) = boundary {
|
||||||
|
let exit_binding_names: Vec<&str> = boundary
|
||||||
|
.exit_bindings
|
||||||
|
.iter()
|
||||||
|
.map(|b| b.carrier_name.as_str())
|
||||||
|
.collect();
|
||||||
|
let carrier_input_names: Vec<&str> =
|
||||||
|
merge_result.carrier_inputs.keys().map(|s| s.as_str()).collect();
|
||||||
|
let exit_phi_names: Vec<&str> =
|
||||||
|
exit_carrier_phis.keys().map(|s| s.as_str()).collect();
|
||||||
|
|
||||||
|
trace.stderr_if(
|
||||||
|
&format!(
|
||||||
|
"[joinir/phase118/dev] exit_bindings carriers={:?}",
|
||||||
|
exit_binding_names
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
trace.stderr_if(
|
||||||
|
&format!(
|
||||||
|
"[joinir/phase118/dev] carrier_inputs keys={:?}",
|
||||||
|
carrier_input_names
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
trace.stderr_if(
|
||||||
|
&format!(
|
||||||
|
"[joinir/phase118/dev] exit_carrier_phis keys={:?}",
|
||||||
|
exit_phi_names
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Phase 246-EX: CRITICAL FIX - Use exit PHI dsts for variable_map reconnection
|
// Phase 246-EX: CRITICAL FIX - Use exit PHI dsts for variable_map reconnection
|
||||||
//
|
//
|
||||||
// **Why EXIT PHI, not HEADER PHI?**
|
// **Why EXIT PHI, not HEADER PHI?**
|
||||||
|
|||||||
@ -127,13 +127,11 @@ pub fn lower_if_sum_pattern(
|
|||||||
// main() locals
|
// main() locals
|
||||||
let i_init_val = alloc_value(); // i = 0
|
let i_init_val = alloc_value(); // i = 0
|
||||||
let sum_init_val = alloc_value(); // sum = 0
|
let sum_init_val = alloc_value(); // sum = 0
|
||||||
let count_init_val = alloc_value(); // count = 0 (optional)
|
|
||||||
let loop_result = alloc_value(); // result from loop_step
|
let loop_result = alloc_value(); // result from loop_step
|
||||||
|
|
||||||
// loop_step params
|
// loop_step params
|
||||||
let i_param = alloc_value();
|
let i_param = alloc_value();
|
||||||
let sum_param = alloc_value();
|
let sum_param = alloc_value();
|
||||||
let count_param = alloc_value();
|
|
||||||
|
|
||||||
// loop_step locals
|
// loop_step locals
|
||||||
// Phase 220-D: loop_limit_val and if_value_val are already allocated by extract_*_condition()
|
// Phase 220-D: loop_limit_val and if_value_val are already allocated by extract_*_condition()
|
||||||
@ -142,19 +140,14 @@ pub fn lower_if_sum_pattern(
|
|||||||
let exit_cond = alloc_value(); // negated loop condition
|
let exit_cond = alloc_value(); // negated loop condition
|
||||||
let if_cmp = alloc_value(); // if condition comparison
|
let if_cmp = alloc_value(); // if condition comparison
|
||||||
let sum_then = alloc_value(); // sum + update_addend
|
let sum_then = alloc_value(); // sum + update_addend
|
||||||
let count_const = alloc_value(); // count increment (1)
|
|
||||||
let count_then = alloc_value(); // count + 1
|
|
||||||
let const_0 = alloc_value(); // 0 for else branch
|
let const_0 = alloc_value(); // 0 for else branch
|
||||||
let sum_else = alloc_value(); // sum + 0 (identity)
|
let sum_else = alloc_value(); // sum + 0 (identity)
|
||||||
let count_else = alloc_value(); // count + 0 (identity)
|
|
||||||
let sum_new = alloc_value(); // Select result for sum
|
let sum_new = alloc_value(); // Select result for sum
|
||||||
let count_new = alloc_value(); // Select result for count
|
|
||||||
let step_const = alloc_value(); // counter step
|
let step_const = alloc_value(); // counter step
|
||||||
let i_next = alloc_value(); // i + step
|
let i_next = alloc_value(); // i + step
|
||||||
|
|
||||||
// k_exit params
|
// k_exit params
|
||||||
let sum_final = alloc_value();
|
let sum_final = alloc_value();
|
||||||
let count_final = alloc_value();
|
|
||||||
|
|
||||||
// === main() function ===
|
// === main() function ===
|
||||||
let mut main_func = JoinFunction::new(main_id, "main".to_string(), vec![]);
|
let mut main_func = JoinFunction::new(main_id, "main".to_string(), vec![]);
|
||||||
@ -171,16 +164,10 @@ pub fn lower_if_sum_pattern(
|
|||||||
value: ConstValue::Integer(0),
|
value: ConstValue::Integer(0),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// count_init = 0
|
// result = loop_step(i_init, sum_init)
|
||||||
main_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
|
||||||
dst: count_init_val,
|
|
||||||
value: ConstValue::Integer(0),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// result = loop_step(i_init, sum_init, count_init)
|
|
||||||
main_func.body.push(JoinInst::Call {
|
main_func.body.push(JoinInst::Call {
|
||||||
func: loop_step_id,
|
func: loop_step_id,
|
||||||
args: vec![i_init_val, sum_init_val, count_init_val],
|
args: vec![i_init_val, sum_init_val],
|
||||||
k_next: None,
|
k_next: None,
|
||||||
dst: Some(loop_result),
|
dst: Some(loop_result),
|
||||||
});
|
});
|
||||||
@ -191,11 +178,11 @@ pub fn lower_if_sum_pattern(
|
|||||||
|
|
||||||
join_module.add_function(main_func);
|
join_module.add_function(main_func);
|
||||||
|
|
||||||
// === loop_step(i, sum, count) function ===
|
// === loop_step(i, sum) function ===
|
||||||
let mut loop_step_func = JoinFunction::new(
|
let mut loop_step_func = JoinFunction::new(
|
||||||
loop_step_id,
|
loop_step_id,
|
||||||
"loop_step".to_string(),
|
"loop_step".to_string(),
|
||||||
vec![i_param, sum_param, count_param],
|
vec![i_param, sum_param],
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- Exit Condition Check ---
|
// --- Exit Condition Check ---
|
||||||
@ -230,7 +217,7 @@ pub fn lower_if_sum_pattern(
|
|||||||
// Jump to exit if condition is false
|
// Jump to exit if condition is false
|
||||||
loop_step_func.body.push(JoinInst::Jump {
|
loop_step_func.body.push(JoinInst::Jump {
|
||||||
cont: k_exit_id.as_cont(),
|
cont: k_exit_id.as_cont(),
|
||||||
args: vec![sum_param, count_param],
|
args: vec![sum_param],
|
||||||
cond: Some(exit_cond),
|
cond: Some(exit_cond),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -270,22 +257,6 @@ pub fn lower_if_sum_pattern(
|
|||||||
rhs: const_0,
|
rhs: const_0,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// count_then = count + 1
|
|
||||||
loop_step_func
|
|
||||||
.body
|
|
||||||
.push(JoinInst::Compute(MirLikeInst::Const {
|
|
||||||
dst: count_const,
|
|
||||||
value: ConstValue::Integer(1),
|
|
||||||
}));
|
|
||||||
loop_step_func
|
|
||||||
.body
|
|
||||||
.push(JoinInst::Compute(MirLikeInst::BinOp {
|
|
||||||
dst: count_then,
|
|
||||||
op: BinOpKind::Add,
|
|
||||||
lhs: count_param,
|
|
||||||
rhs: count_const,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// --- Else Branch ---
|
// --- Else Branch ---
|
||||||
// sum_else = sum + 0 (identity)
|
// sum_else = sum + 0 (identity)
|
||||||
loop_step_func
|
loop_step_func
|
||||||
@ -303,16 +274,6 @@ pub fn lower_if_sum_pattern(
|
|||||||
rhs: step_const,
|
rhs: step_const,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// count_else = count + 0 (identity)
|
|
||||||
loop_step_func
|
|
||||||
.body
|
|
||||||
.push(JoinInst::Compute(MirLikeInst::BinOp {
|
|
||||||
dst: count_else,
|
|
||||||
op: BinOpKind::Add,
|
|
||||||
lhs: count_param,
|
|
||||||
rhs: step_const, // 0
|
|
||||||
}));
|
|
||||||
|
|
||||||
// --- Select ---
|
// --- Select ---
|
||||||
loop_step_func
|
loop_step_func
|
||||||
.body
|
.body
|
||||||
@ -323,15 +284,6 @@ pub fn lower_if_sum_pattern(
|
|||||||
else_val: sum_else,
|
else_val: sum_else,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
loop_step_func
|
|
||||||
.body
|
|
||||||
.push(JoinInst::Compute(MirLikeInst::Select {
|
|
||||||
dst: count_new,
|
|
||||||
cond: if_cmp,
|
|
||||||
then_val: count_then,
|
|
||||||
else_val: count_else,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// --- Counter Update ---
|
// --- Counter Update ---
|
||||||
let step_const2 = alloc_value();
|
let step_const2 = alloc_value();
|
||||||
loop_step_func
|
loop_step_func
|
||||||
@ -352,19 +304,15 @@ pub fn lower_if_sum_pattern(
|
|||||||
// --- Tail Recursion ---
|
// --- Tail Recursion ---
|
||||||
loop_step_func.body.push(JoinInst::Call {
|
loop_step_func.body.push(JoinInst::Call {
|
||||||
func: loop_step_id,
|
func: loop_step_id,
|
||||||
args: vec![i_next, sum_new, count_new],
|
args: vec![i_next, sum_new],
|
||||||
k_next: None,
|
k_next: None,
|
||||||
dst: None,
|
dst: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
join_module.add_function(loop_step_func);
|
join_module.add_function(loop_step_func);
|
||||||
|
|
||||||
// === k_exit(sum_final, count_final) function ===
|
// === k_exit(sum_final) function ===
|
||||||
let mut k_exit_func = JoinFunction::new(
|
let mut k_exit_func = JoinFunction::new(k_exit_id, "k_exit".to_string(), vec![sum_final]);
|
||||||
k_exit_id,
|
|
||||||
"k_exit".to_string(),
|
|
||||||
vec![sum_final, count_final],
|
|
||||||
);
|
|
||||||
|
|
||||||
k_exit_func.body.push(JoinInst::Ret {
|
k_exit_func.body.push(JoinInst::Ret {
|
||||||
value: Some(sum_final),
|
value: Some(sum_final),
|
||||||
@ -374,9 +322,9 @@ pub fn lower_if_sum_pattern(
|
|||||||
join_module.entry = Some(main_id);
|
join_module.entry = Some(main_id);
|
||||||
|
|
||||||
// Build ExitMeta
|
// Build ExitMeta
|
||||||
|
// SSOT: use the accumulator name extracted from AST (no hardcoded carrier names).
|
||||||
let mut exit_values = vec![];
|
let mut exit_values = vec![];
|
||||||
exit_values.push(("sum".to_string(), sum_final));
|
exit_values.push((update_var.clone(), sum_final));
|
||||||
exit_values.push(("count".to_string(), count_final));
|
|
||||||
|
|
||||||
let exit_meta = ExitMeta::multiple(exit_values);
|
let exit_meta = ExitMeta::multiple(exit_values);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user