stage3: unify to cleanup; MIR return-defer; docs+smokes updated; LLVM(harness): finalize_phis ownership, ret.py simplified, uses-predeclare; cleanup return override green; method-postfix cleanup return WIP (PHI head)
This commit is contained in:
102
src/mir/builder/if_form.rs
Normal file
102
src/mir/builder/if_form.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use super::{ConstValue, MirBuilder, MirInstruction, ValueId};
|
||||
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
|
||||
use crate::ast::ASTNode;
|
||||
|
||||
impl MirBuilder {
|
||||
/// Lower an if/else using a structured IfForm (header→then/else→merge).
|
||||
/// PHI-off: edge-copy only on predecessors; PHI-on: Phi at merge.
|
||||
pub(super) fn lower_if_form(
|
||||
&mut self,
|
||||
condition: ASTNode,
|
||||
then_branch: ASTNode,
|
||||
else_branch: Option<ASTNode>,
|
||||
) -> Result<ValueId, String> {
|
||||
let condition_val = self.build_expression(condition)?;
|
||||
|
||||
// Create blocks
|
||||
let then_block = self.block_gen.next();
|
||||
let else_block = self.block_gen.next();
|
||||
let merge_block = self.block_gen.next();
|
||||
|
||||
// Branch
|
||||
self.emit_instruction(MirInstruction::Branch {
|
||||
condition: condition_val,
|
||||
then_bb: then_block,
|
||||
else_bb: else_block,
|
||||
})?;
|
||||
|
||||
// Snapshot variables before entering branches
|
||||
let pre_if_var_map = self.variable_map.clone();
|
||||
|
||||
// then
|
||||
self.current_block = Some(then_block);
|
||||
self.ensure_block_exists(then_block)?;
|
||||
let then_ast_for_analysis = then_branch.clone();
|
||||
self.variable_map = pre_if_var_map.clone();
|
||||
let then_value_raw = self.build_expression(then_branch)?;
|
||||
let then_exit_block = self.current_block()?;
|
||||
let then_var_map_end = self.variable_map.clone();
|
||||
if !self.is_current_block_terminated() {
|
||||
self.emit_instruction(MirInstruction::Jump { target: merge_block })?;
|
||||
}
|
||||
|
||||
// else
|
||||
self.current_block = Some(else_block);
|
||||
self.ensure_block_exists(else_block)?;
|
||||
let (else_value_raw, else_ast_for_analysis, else_var_map_end_opt) = if let Some(else_ast) = else_branch {
|
||||
self.variable_map = pre_if_var_map.clone();
|
||||
let val = self.build_expression(else_ast.clone())?;
|
||||
(val, Some(else_ast), Some(self.variable_map.clone()))
|
||||
} else {
|
||||
let void_val = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const { dst: void_val, value: ConstValue::Void })?;
|
||||
(void_val, None, None)
|
||||
};
|
||||
let else_exit_block = self.current_block()?;
|
||||
if !self.is_current_block_terminated() {
|
||||
self.emit_instruction(MirInstruction::Jump { target: merge_block })?;
|
||||
}
|
||||
|
||||
// merge: primary result via helper, then delta-based variable merges
|
||||
self.current_block = Some(merge_block);
|
||||
self.ensure_block_exists(merge_block)?;
|
||||
self.push_if_merge(merge_block);
|
||||
|
||||
// Pre-analysis: identify then-assigned var for skip
|
||||
let assigned_then_pre = super::phi::extract_assigned_var(&then_ast_for_analysis);
|
||||
let pre_then_var_value = assigned_then_pre
|
||||
.as_ref()
|
||||
.and_then(|name| pre_if_var_map.get(name).copied());
|
||||
|
||||
let result_val = self.normalize_if_else_phi(
|
||||
then_block,
|
||||
else_block,
|
||||
Some(then_exit_block),
|
||||
Some(else_exit_block),
|
||||
then_value_raw,
|
||||
else_value_raw,
|
||||
&pre_if_var_map,
|
||||
&then_ast_for_analysis,
|
||||
&else_ast_for_analysis,
|
||||
&then_var_map_end,
|
||||
&else_var_map_end_opt,
|
||||
pre_then_var_value,
|
||||
)?;
|
||||
|
||||
// Merge other modified variables (skip the primary assignment if any)
|
||||
let skip_name = assigned_then_pre.as_deref();
|
||||
self.merge_modified_vars(
|
||||
then_block,
|
||||
else_block,
|
||||
then_exit_block,
|
||||
Some(else_exit_block),
|
||||
&pre_if_var_map,
|
||||
&then_var_map_end,
|
||||
&else_var_map_end_opt,
|
||||
skip_name,
|
||||
)?;
|
||||
|
||||
self.pop_if_merge();
|
||||
Ok(result_val)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user