builder: pre-pin comparison operands in if_form and loop_builder (lower_if_in_loop/build_loop) to slots; utils: pin_to_slot pub(crate) and entry materialize for pinned slots only; continue JSON VM debug
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
use super::{ConstValue, MirBuilder, MirInstruction, ValueId};
|
||||
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
|
||||
use crate::ast::ASTNode;
|
||||
use crate::ast::{ASTNode, BinaryOperator};
|
||||
|
||||
impl MirBuilder {
|
||||
/// Lower an if/else using a structured IfForm (header→then/else→merge).
|
||||
@ -11,6 +11,28 @@ impl MirBuilder {
|
||||
then_branch: ASTNode,
|
||||
else_branch: Option<ASTNode>,
|
||||
) -> Result<ValueId, String> {
|
||||
// Heuristic pre-pin: if condition is a comparison, evaluate its operands now and pin them
|
||||
// so that subsequent branches can safely reuse these values across blocks.
|
||||
// This leverages existing variable_map merges (PHI) at the merge block.
|
||||
if let ASTNode::BinaryOp { operator, left, right, .. } = &condition {
|
||||
match operator {
|
||||
BinaryOperator::Equal
|
||||
| BinaryOperator::NotEqual
|
||||
| BinaryOperator::Less
|
||||
| BinaryOperator::LessEqual
|
||||
| BinaryOperator::Greater
|
||||
| BinaryOperator::GreaterEqual => {
|
||||
if let Ok(lhs_v) = self.build_expression((**left).clone()) {
|
||||
let _ = self.pin_to_slot(lhs_v, "@if_lhs");
|
||||
}
|
||||
if let Ok(rhs_v) = self.build_expression((**right).clone()) {
|
||||
let _ = self.pin_to_slot(rhs_v, "@if_rhs");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let condition_val = self.build_expression(condition)?;
|
||||
|
||||
// Create blocks
|
||||
|
||||
@ -58,7 +58,7 @@ impl super::MirBuilder {
|
||||
// Comparison operations
|
||||
BinaryOpType::Comparison(op) => {
|
||||
// 80/20: If both operands originate from IntegerBox, cast to integer first
|
||||
let (lhs2, rhs2) = if self
|
||||
let (lhs2_raw, rhs2_raw) = if self
|
||||
.value_origin_newbox
|
||||
.get(&lhs)
|
||||
.map(|s| s == "IntegerBox")
|
||||
@ -87,6 +87,9 @@ impl super::MirBuilder {
|
||||
} else {
|
||||
(lhs, rhs)
|
||||
};
|
||||
// Materialize operands in the current block to avoid dominance/undef issues
|
||||
let lhs2 = lhs2_raw;
|
||||
let rhs2 = rhs2_raw;
|
||||
self.emit_instruction(MirInstruction::Compare {
|
||||
dst,
|
||||
op,
|
||||
@ -110,8 +113,9 @@ impl super::MirBuilder {
|
||||
) -> Result<ValueId, String> {
|
||||
let is_and = matches!(operator, BinaryOperator::And);
|
||||
|
||||
// Evaluate LHS only once
|
||||
let lhs_val = self.build_expression(left)?;
|
||||
// Evaluate LHS only once and pin to a slot so it can be reused safely across blocks
|
||||
let lhs_val0 = self.build_expression(left)?;
|
||||
let lhs_val = self.pin_to_slot(lhs_val0, "@sc_lhs")?;
|
||||
|
||||
// Prepare blocks
|
||||
let then_block = self.block_gen.next();
|
||||
|
||||
@ -32,6 +32,17 @@ impl super::MirBuilder {
|
||||
if let Some(ref mut function) = self.current_function {
|
||||
function.add_block(BasicBlock::new(block_id));
|
||||
self.current_block = Some(block_id);
|
||||
// Entry materialization for pinned slots only: ensure a local def exists in this block
|
||||
// This avoids dominance/undef issues when pinned values are referenced across blocks.
|
||||
let names: Vec<String> = self.variable_map.keys().cloned().collect();
|
||||
for name in names {
|
||||
if !name.starts_with("__pin$") { continue; }
|
||||
if let Some(&src) = self.variable_map.get(&name) {
|
||||
let dst = self.value_gen.next();
|
||||
self.emit_instruction(super::MirInstruction::Copy { dst, src })?;
|
||||
self.variable_map.insert(name.clone(), dst);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err("No current function".to_string())
|
||||
@ -192,4 +203,21 @@ impl super::MirBuilder {
|
||||
ptr,
|
||||
})
|
||||
}
|
||||
|
||||
/// Pin a block-crossing ephemeral value into a pseudo local slot so it participates in PHI merges.
|
||||
pub(crate) fn pin_to_slot(&mut self, v: super::ValueId, hint: &str) -> Result<super::ValueId, String> {
|
||||
self.temp_slot_counter = self.temp_slot_counter.wrapping_add(1);
|
||||
let slot_name = format!("__pin${}${}", self.temp_slot_counter, hint);
|
||||
let dst = self.value_gen.next();
|
||||
self.emit_instruction(super::MirInstruction::Copy { dst, src: v })?;
|
||||
self.variable_map.insert(slot_name, dst);
|
||||
Ok(dst)
|
||||
}
|
||||
|
||||
/// Ensure a value has a local definition in the current block by inserting a Copy.
|
||||
pub(crate) fn materialize_local(&mut self, v: super::ValueId) -> Result<super::ValueId, String> {
|
||||
let dst = self.value_gen.next();
|
||||
self.emit_instruction(super::MirInstruction::Copy { dst, src: v })?;
|
||||
Ok(dst)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user