builder: add loop helpers (create_loop_blocks/add_predecessor) and adopt in LoopBuilder; use BinaryExpr/CallExpr wrappers in expr lowering (no behavior change)

This commit is contained in:
Selfhosting Dev
2025-09-17 07:59:41 +09:00
parent f3be8ea5f6
commit 6b505b5435
3 changed files with 44 additions and 26 deletions

View File

@ -1,6 +1,6 @@
// Expression lowering split from builder.rs to keep files lean // Expression lowering split from builder.rs to keep files lean
use super::{ConstValue, MirInstruction, ValueId}; use super::{ConstValue, MirInstruction, ValueId};
use crate::ast::{ASTNode, AssignStmt, ReturnStmt}; use crate::ast::{ASTNode, AssignStmt, ReturnStmt, BinaryExpr, CallExpr};
impl super::MirBuilder { impl super::MirBuilder {
// Main expression dispatcher // Main expression dispatcher
@ -19,12 +19,11 @@ impl super::MirBuilder {
match ast { match ast {
ASTNode::Literal { value, .. } => self.build_literal(value), ASTNode::Literal { value, .. } => self.build_literal(value),
ASTNode::BinaryOp { node @ ASTNode::BinaryOp { .. } => {
left, // Use BinaryExpr for clear destructuring (no behavior change)
operator, let e = BinaryExpr::try_from(node).expect("ASTNode::BinaryOp must convert");
right, self.build_binary_op(*e.left, e.operator, *e.right)
.. }
} => self.build_binary_op(*left, operator, *right),
ASTNode::UnaryOp { ASTNode::UnaryOp {
operator, operand, .. operator, operand, ..
@ -87,9 +86,10 @@ impl super::MirBuilder {
} }
} }
ASTNode::FunctionCall { node @ ASTNode::FunctionCall { .. } => {
name, arguments, .. let c = CallExpr::try_from(node).expect("ASTNode::FunctionCall must convert");
} => self.build_function_call(name.clone(), arguments.clone()), self.build_function_call(c.name, c.arguments)
}
ASTNode::Call { ASTNode::Call {
callee, arguments, .. callee, arguments, ..

View File

@ -1,5 +1,14 @@
//! Small loop utilities for MirBuilder //! Small loop utilities for MirBuilder
use super::BasicBlockId; use super::{BasicBlockId, MirBuilder};
/// Create header/body/after blocks for a loop and push loop context.
pub(crate) fn create_loop_blocks(builder: &mut MirBuilder) -> (BasicBlockId, BasicBlockId, BasicBlockId) {
let header = builder.block_gen.next();
let body = builder.block_gen.next();
let after = builder.block_gen.next();
push_loop_context(builder, header, after);
(header, body, after)
}
/// Push loop context (header/exit) onto the MirBuilder stacks. /// Push loop context (header/exit) onto the MirBuilder stacks.
pub(crate) fn push_loop_context( pub(crate) fn push_loop_context(
@ -36,3 +45,19 @@ pub(crate) fn in_loop(builder: &super::MirBuilder) -> bool {
pub(crate) fn depth(builder: &super::MirBuilder) -> usize { pub(crate) fn depth(builder: &super::MirBuilder) -> usize {
builder.loop_header_stack.len() builder.loop_header_stack.len()
} }
/// Add predecessor edge metadata to a basic block.
pub(crate) fn add_predecessor(
builder: &mut MirBuilder,
block: BasicBlockId,
pred: BasicBlockId,
) -> Result<(), String> {
if let Some(ref mut function) = builder.current_function {
if let Some(bb) = function.get_block_mut(block) {
bb.add_predecessor(pred);
return Ok(());
}
return Err(format!("Block {} not found", block));
}
Err("No current function".to_string())
}

View File

@ -103,21 +103,14 @@ impl<'a> LoopBuilder<'a> {
) -> Result<ValueId, String> { ) -> Result<ValueId, String> {
// 1. ブロックの準備 // 1. ブロックの準備
let preheader_id = self.current_block()?; let preheader_id = self.current_block()?;
let header_id = self.new_block(); let (header_id, body_id, after_loop_id) =
let body_id = self.new_block(); crate::mir::builder::loops::create_loop_blocks(self.parent_builder);
let after_loop_id = self.new_block();
self.loop_header = Some(header_id); self.loop_header = Some(header_id);
self.continue_snapshots.clear(); self.continue_snapshots.clear();
// Push loop context to parent builder (for nested break/continue lowering)
crate::mir::builder::loops::push_loop_context(
self.parent_builder,
header_id,
after_loop_id,
);
// 2. Preheader -> Header へのジャンプ // 2. Preheader -> Header へのジャンプ
self.emit_jump(header_id)?; self.emit_jump(header_id)?;
let _ = self.add_predecessor(header_id, preheader_id); let _ = crate::mir::builder::loops::add_predecessor(self.parent_builder, header_id, preheader_id);
// 3. Headerブロックの準備unsealed状態 // 3. Headerブロックの準備unsealed状態
self.set_current_block(header_id)?; self.set_current_block(header_id)?;
@ -133,8 +126,8 @@ impl<'a> LoopBuilder<'a> {
// 6. 条件分岐 // 6. 条件分岐
self.emit_branch(condition_value, body_id, after_loop_id)?; self.emit_branch(condition_value, body_id, after_loop_id)?;
let _ = self.add_predecessor(body_id, header_id); let _ = crate::mir::builder::loops::add_predecessor(self.parent_builder, body_id, header_id);
let _ = self.add_predecessor(after_loop_id, header_id); let _ = crate::mir::builder::loops::add_predecessor(self.parent_builder, after_loop_id, header_id);
// 7. ループボディの構築 // 7. ループボディの構築
self.set_current_block(body_id)?; self.set_current_block(body_id)?;
@ -159,7 +152,7 @@ impl<'a> LoopBuilder<'a> {
// 実際の latch_id に対してスナップショットを紐づける // 実際の latch_id に対してスナップショットを紐づける
self.block_var_maps.insert(latch_id, latch_snapshot); self.block_var_maps.insert(latch_id, latch_snapshot);
self.emit_jump(header_id)?; self.emit_jump(header_id)?;
let _ = self.add_predecessor(header_id, latch_id); let _ = crate::mir::builder::loops::add_predecessor(self.parent_builder, header_id, latch_id);
// 9. Headerブロックをシール全predecessors確定 // 9. Headerブロックをシール全predecessors確定
self.seal_block(header_id, latch_id)?; self.seal_block(header_id, latch_id)?;
@ -539,7 +532,7 @@ impl<'a> LoopBuilder<'a> {
let cur_block = self.current_block()?; let cur_block = self.current_block()?;
if let Some(exit_bb) = crate::mir::builder::loops::current_exit(self.parent_builder) { if let Some(exit_bb) = crate::mir::builder::loops::current_exit(self.parent_builder) {
self.emit_jump(exit_bb)?; self.emit_jump(exit_bb)?;
let _ = self.add_predecessor(exit_bb, cur_block); let _ = crate::mir::builder::loops::add_predecessor(self.parent_builder, exit_bb, cur_block);
} }
// Continue building in a fresh (unreachable) block to satisfy callers // Continue building in a fresh (unreachable) block to satisfy callers
let next_block = self.new_block(); let next_block = self.new_block();
@ -556,7 +549,7 @@ impl<'a> LoopBuilder<'a> {
if let Some(header) = self.loop_header { if let Some(header) = self.loop_header {
self.emit_jump(header)?; self.emit_jump(header)?;
let _ = self.add_predecessor(header, cur_block); let _ = crate::mir::builder::loops::add_predecessor(self.parent_builder, header, cur_block);
} }
let next_block = self.new_block(); let next_block = self.new_block();