refactor(joinir): Phase 190 convert.rs modularization

- Created joinir_function_converter.rs (~133 lines): Function-level conversion
- Created joinir_block_converter.rs (~691 lines): Block-level conversion
- Reduced convert.rs from 943 → 120 lines (87% reduction)
- Total: 944 lines (original 943 lines, minimal overhead)
- Separation of concerns: Function vs Block responsibilities
- All handlers moved to block_converter for better organization
- Maintained backward compatibility with existing API
- Build successful, simple tests passing
This commit is contained in:
nyash-codex
2025-12-05 14:41:24 +09:00
parent 827990e742
commit 7c55baa818
14 changed files with 1078 additions and 1154 deletions

View File

@ -0,0 +1,141 @@
# Phase 33-11: Exit Block PHI Node Missing Bug Analysis
## Problem Summary
The MIR generated from JoinIR lowering is missing PHI nodes in the exit block, causing "use of undefined value" errors.
## Test Case
File: `apps/tests/loop_min_while.hako`
```nyash
static box Main {
main() {
local i = 0
loop(i < 3) {
print(i)
i = i + 1
}
return 0
}
}
```
## Error
```
[ERROR] use of undefined value ValueId(16)
```
## MIR Dump Analysis
```mir
bb8:
1: ret %16 # %16 is never defined!
```
bb8 is the exit block, but ValueId(16) is never defined anywhere.
## Root Cause
In `src/mir/builder/control_flow.rs::merge_joinir_mir_blocks()`:
### Step 1: Exit block is created empty (line 618-621)
```rust
let exit_block_id = self.block_gen.next();
// ...
let exit_block = BasicBlock::new(exit_block_id); // Empty!
func.add_block(exit_block);
```
### Step 2: Return instructions are converted to Jump (line 827-841)
```rust
MirInstruction::Return { value } => {
if let Some(ret_val) = value {
let remapped_val = value_map.get(ret_val).copied().unwrap_or(*ret_val);
if debug {
eprintln!(
"[cf_loop/joinir] Return({:?}) → Jump to exit",
remapped_val
);
}
}
MirInstruction::Jump {
target: exit_block_id,
}
}
```
**Problem**: The return value (`remapped_val`) is logged but NOT STORED anywhere!
### Step 3: Exit block stays empty
The exit block is never populated with:
- PHI nodes to collect return values
- Return instruction to return the PHI'd value
## Expected Fix
The exit block should look like:
```mir
bb8:
1: %16 = phi [%9 from bb7], [%2 from bb5], ...
1: ret %16
```
Or simpler, if all functions return the same constant:
```mir
bb8:
1: %16 = const 0
1: ret %16
```
## JoinIR Functions Structure
The Pattern 1 lowerer generates 3 functions:
1. **main()**: Calls loop_step, returns 0
2. **loop_step()**: Tail recursion OR Jump to k_exit
3. **k_exit()**: Returns 0
All Return instructions are converted to Jump to bb8 (exit block).
## Solution Strategy
### Option A: Collect Return Values + Generate PHI
1. While converting Return→Jump, collect all return values
2. After merging, generate PHI node in exit block
3. Add Return instruction that returns PHI result
### Option B: Direct Value Propagation
1. Since Pattern 1 always returns 0, directly emit const 0 in exit block
2. Simpler but less general
### Option C: Track Return Values in Hash Map
1. Create `HashMap<BasicBlockId, ValueId>` to track returns
2. Use as PHI incoming values
3. Most robust, handles all patterns
## Recommendation
Start with **Option B** (simplest fix for Pattern 1), then generalize to **Option C** for future patterns.
## Implementation Location
File: `src/mir/builder/control_flow.rs`
Function: `merge_joinir_mir_blocks()`
Lines: ~827-950
## Test Validation
```bash
NYASH_DISABLE_PLUGINS=1 ./target/release/hakorune apps/tests/loop_min_while.hako
```
Expected output:
```
0
1
2
```

View File

@ -557,6 +557,8 @@ impl super::MirBuilder {
) -> Result<(), String> { ) -> Result<(), String> {
use crate::mir::{BasicBlock, BasicBlockId, MirInstruction, ValueId}; use crate::mir::{BasicBlock, BasicBlockId, MirInstruction, ValueId};
use std::collections::HashMap; use std::collections::HashMap;
// Phase 189: Use new ID remapper Box
use super::joinir_id_remapper::JoinIrIdRemapper;
if debug { if debug {
eprintln!( eprintln!(
@ -565,11 +567,9 @@ impl super::MirBuilder {
); );
} }
// Phase 189: Global ID maps for ALL functions (not just first) // Phase 189: Create ID remapper for ValueId/BlockId translation
// CRITICAL: Use composite keys (func_name, BasicBlockId) to avoid collisions! let mut remapper = JoinIrIdRemapper::new();
// Different functions can have blocks with same BasicBlockId (e.g., both have bb0)
let mut block_map: HashMap<(String, BasicBlockId), BasicBlockId> = HashMap::new();
let mut value_map: HashMap<ValueId, ValueId> = HashMap::new();
// Phase 189: Map function names to their entry blocks (for Call→Jump conversion) // Phase 189: Map function names to their entry blocks (for Call→Jump conversion)
let mut function_entry_map: HashMap<String, BasicBlockId> = HashMap::new(); let mut function_entry_map: HashMap<String, BasicBlockId> = HashMap::new();
@ -589,8 +589,8 @@ impl super::MirBuilder {
blocks.sort_by_key(|(id, _)| id.0); blocks.sort_by_key(|(id, _)| id.0);
for (old_block_id, _) in blocks { for (old_block_id, _) in blocks {
let new_block_id = self.block_gen.next(); let new_block_id = self.block_gen.next();
// Use composite key to avoid collision between functions // Use remapper to store composite key mapping
block_map.insert((func_name.clone(), *old_block_id), new_block_id); remapper.set_block(func_name.clone(), *old_block_id, new_block_id);
if debug { if debug {
eprintln!( eprintln!(
"[cf_loop/joinir] Block remap: {}:{:?}{:?}", "[cf_loop/joinir] Block remap: {}:{:?}{:?}",
@ -599,7 +599,8 @@ impl super::MirBuilder {
} }
} }
// Map function entry blocks for Call→Jump conversion // Map function entry blocks for Call→Jump conversion
let entry_block_new = block_map[&(func_name.clone(), func.entry_block)]; let entry_block_new = remapper.get_block(func_name, func.entry_block)
.ok_or_else(|| format!("Entry block not found for {}", func_name))?;
function_entry_map.insert(func_name.clone(), entry_block_new); function_entry_map.insert(func_name.clone(), entry_block_new);
if debug { if debug {
eprintln!( eprintln!(
@ -631,7 +632,10 @@ impl super::MirBuilder {
function_params.insert(func_name.clone(), func.params.clone()); function_params.insert(func_name.clone(), func.params.clone());
for block in func.blocks.values() { for block in func.blocks.values() {
Self::collect_values_in_block(block, &mut used_values); // Phase 189: Use remapper to collect values
let block_values = remapper.collect_values_in_block(block);
used_values.extend(block_values);
// Phase 189: Track Const String instructions that define function names // Phase 189: Track Const String instructions that define function names
for inst in &block.instructions { for inst in &block.instructions {
if let MirInstruction::Const { dst, value } = inst { if let MirInstruction::Const { dst, value } = inst {
@ -658,7 +662,7 @@ impl super::MirBuilder {
// 4. Allocate new ValueIds for all collected values // 4. Allocate new ValueIds for all collected values
for old_value in used_values { for old_value in used_values {
let new_value = self.next_value_id(); let new_value = self.next_value_id();
value_map.insert(old_value, new_value); remapper.set_value(old_value, new_value);
if debug { if debug {
eprintln!( eprintln!(
"[cf_loop/joinir] Value remap: {:?}{:?}", "[cf_loop/joinir] Value remap: {:?}{:?}",
@ -688,7 +692,8 @@ impl super::MirBuilder {
// Build a local block map for this function (for remap_instruction compatibility) // Build a local block map for this function (for remap_instruction compatibility)
let mut local_block_map: HashMap<BasicBlockId, BasicBlockId> = HashMap::new(); let mut local_block_map: HashMap<BasicBlockId, BasicBlockId> = HashMap::new();
for old_block_id in func.blocks.keys() { for old_block_id in func.blocks.keys() {
let new_block_id = block_map[&(func_name.clone(), *old_block_id)]; let new_block_id = remapper.get_block(func_name, *old_block_id)
.ok_or_else(|| format!("Block {:?} not found for {}", old_block_id, func_name))?;
local_block_map.insert(*old_block_id, new_block_id); local_block_map.insert(*old_block_id, new_block_id);
} }
@ -697,8 +702,9 @@ impl super::MirBuilder {
let mut blocks_merge: Vec<_> = func.blocks.iter().collect(); let mut blocks_merge: Vec<_> = func.blocks.iter().collect();
blocks_merge.sort_by_key(|(id, _)| id.0); blocks_merge.sort_by_key(|(id, _)| id.0);
for (old_block_id, old_block) in blocks_merge { for (old_block_id, old_block) in blocks_merge {
// Use composite key to get correct mapping for this function's block // Use remapper to get correct mapping for this function's block
let new_block_id = block_map[&(func_name.clone(), *old_block_id)]; let new_block_id = remapper.get_block(func_name, *old_block_id)
.ok_or_else(|| format!("Block {:?} not found for {}", old_block_id, func_name))?;
let mut new_block = BasicBlock::new(new_block_id); let mut new_block = BasicBlock::new(new_block_id);
// Remap instructions (Phase 189: Convert inter-function Calls to control flow) // Remap instructions (Phase 189: Convert inter-function Calls to control flow)
@ -726,7 +732,7 @@ impl super::MirBuilder {
// This is a tail call - save info and skip the Call instruction itself // This is a tail call - save info and skip the Call instruction itself
let remapped_args: Vec<ValueId> = args let remapped_args: Vec<ValueId> = args
.iter() .iter()
.map(|&v| value_map.get(&v).copied().unwrap_or(v)) .map(|&v| remapper.get_value(v).unwrap_or(v))
.collect(); .collect();
tail_call_target = Some((target_block, remapped_args)); tail_call_target = Some((target_block, remapped_args));
found_tail_call = true; found_tail_call = true;
@ -742,15 +748,29 @@ impl super::MirBuilder {
} }
} }
// Process regular instructions // Process regular instructions - Phase 189: Use remapper.remap_instruction() + manual block remapping
let remapped = Self::remap_joinir_instruction( let remapped = remapper.remap_instruction(inst);
inst,
&value_map, // Phase 189 FIX: Manual block remapping for Branch/Phi (JoinIrIdRemapper doesn't know func_name)
&local_block_map, // Use local map for this function let remapped_with_blocks = match remapped {
&function_entry_map, MirInstruction::Branch { condition, then_bb, else_bb } => {
&value_to_func_name, MirInstruction::Branch {
debug, condition,
); then_bb: local_block_map.get(&then_bb).copied().unwrap_or(then_bb),
else_bb: local_block_map.get(&else_bb).copied().unwrap_or(else_bb),
}
}
MirInstruction::Phi { dst, inputs, type_hint: None } => {
MirInstruction::Phi {
dst,
inputs: inputs.iter().map(|(bb, val)| {
(local_block_map.get(bb).copied().unwrap_or(*bb), *val)
}).collect(),
type_hint: None,
}
}
other => other,
};
if debug { if debug {
match inst { match inst {
@ -761,7 +781,7 @@ impl super::MirBuilder {
} }
} }
new_block.instructions.push(remapped); new_block.instructions.push(remapped_with_blocks);
} }
// Second pass: Insert parameter bindings for tail calls // Second pass: Insert parameter bindings for tail calls
@ -790,7 +810,7 @@ impl super::MirBuilder {
for (i, arg_val_remapped) in args.iter().enumerate() { for (i, arg_val_remapped) in args.iter().enumerate() {
if i < target_params.len() { if i < target_params.len() {
let param_val_original = target_params[i]; let param_val_original = target_params[i];
if let Some(&param_val_remapped) = value_map.get(&param_val_original) { if let Some(param_val_remapped) = remapper.get_value(param_val_original) {
new_block.instructions.push(MirInstruction::Copy { new_block.instructions.push(MirInstruction::Copy {
dst: param_val_remapped, dst: param_val_remapped,
src: *arg_val_remapped, src: *arg_val_remapped,
@ -823,7 +843,7 @@ impl super::MirBuilder {
// Convert Return to Jump to exit block // Convert Return to Jump to exit block
// All functions return to same exit block (Phase 189) // All functions return to same exit block (Phase 189)
if let Some(ret_val) = value { if let Some(ret_val) = value {
let remapped_val = value_map.get(ret_val).copied().unwrap_or(*ret_val); let remapped_val = remapper.get_value(*ret_val).unwrap_or(*ret_val);
if debug { if debug {
eprintln!( eprintln!(
"[cf_loop/joinir] Return({:?}) → Jump to exit", "[cf_loop/joinir] Return({:?}) → Jump to exit",
@ -835,14 +855,27 @@ impl super::MirBuilder {
target: exit_block_id, target: exit_block_id,
} }
} }
_ => Self::remap_joinir_instruction( MirInstruction::Jump { target } => {
term, // Phase 189 FIX: Remap block ID for Jump
&value_map, MirInstruction::Jump {
&local_block_map, // Use local map for this function target: local_block_map.get(target).copied().unwrap_or(*target),
&function_entry_map, }
&value_to_func_name, }
debug, MirInstruction::Branch { condition, then_bb, else_bb } => {
), // Phase 189 FIX: Remap block IDs for Branch
let remapped = remapper.remap_instruction(term);
match remapped {
MirInstruction::Branch { condition, then_bb, else_bb } => {
MirInstruction::Branch {
condition,
then_bb: local_block_map.get(&then_bb).copied().unwrap_or(then_bb),
else_bb: local_block_map.get(&else_bb).copied().unwrap_or(else_bb),
}
}
other => other,
}
}
_ => remapper.remap_instruction(term),
}; };
new_block.terminator = Some(remapped_term); new_block.terminator = Some(remapped_term);
} }
@ -855,59 +888,36 @@ impl super::MirBuilder {
} }
} }
// Phase 188-Impl-3: Inject Copy instructions for boundary inputs // Phase 188-Impl-3: Inject Copy instructions for boundary inputs using BoundaryInjector
if let Some(boundary) = boundary { if let Some(boundary) = boundary {
use super::joinir_inline_boundary_injector::BoundaryInjector;
// Get entry function's entry block (first function by convention) // Get entry function's entry block (first function by convention)
let (entry_func_name, entry_func) = mir_module let (entry_func_name, entry_func) = mir_module
.functions .functions
.iter() .iter()
.next() .next()
.ok_or("JoinIR module has no functions")?; .ok_or("JoinIR module has no functions")?;
let entry_block_remapped = block_map[&(entry_func_name.clone(), entry_func.entry_block)]; let entry_block_remapped = remapper.get_block(entry_func_name, entry_func.entry_block)
.ok_or_else(|| format!("Entry block not found for {}", entry_func_name))?;
if debug { // Create HashMap from remapper for BoundaryInjector (temporary adapter)
eprintln!( let mut value_map_for_injector = HashMap::new();
"[cf_loop/joinir] Phase 188-Impl-3: Injecting {} Copy instructions at entry block {:?}", for join_in in &boundary.join_inputs {
boundary.join_inputs.len(), if let Some(remapped) = remapper.get_value(*join_in) {
entry_block_remapped value_map_for_injector.insert(*join_in, remapped);
); }
} }
// Inject Copy instructions: join_input_remapped = Copy host_input // Use BoundaryInjector to inject Copy instructions
if let Some(ref mut current_func) = self.current_function { if let Some(ref mut current_func) = self.current_function {
if let Some(entry_block) = current_func.get_block_mut(entry_block_remapped) { BoundaryInjector::inject_boundary_copies(
// Insert Copy instructions at the BEGINNING of the block current_func,
let mut copy_instructions = Vec::new(); entry_block_remapped,
for (join_in, host_in) in boundary.join_inputs.iter().zip(&boundary.host_inputs) { boundary,
// join_in is JoinIR's local ValueId (e.g., ValueId(0)) &value_map_for_injector,
// host_in is host function's ValueId (e.g., ValueId(4)) debug,
// We need to remap join_in to the merged space )?;
if let Some(&join_in_remapped) = value_map.get(join_in) {
copy_instructions.push(MirInstruction::Copy {
dst: join_in_remapped,
src: *host_in,
});
if debug {
eprintln!(
"[cf_loop/joinir] Copy boundary: {:?} (host) → {:?} (join_remapped)",
host_in, join_in_remapped
);
}
} else {
if debug {
eprintln!(
"[cf_loop/joinir] WARNING: join_input {:?} not found in value_map",
join_in
);
}
}
}
// Insert at beginning (reverse order so they appear in correct order)
for inst in copy_instructions.into_iter().rev() {
entry_block.instructions.insert(0, inst);
}
}
} }
} }
@ -924,8 +934,9 @@ impl super::MirBuilder {
.iter() .iter()
.next() .next()
.ok_or("JoinIR module has no functions")?; .ok_or("JoinIR module has no functions")?;
// Use composite key to get entry block mapping // Use remapper to get entry block mapping
let entry_block = block_map[&(entry_func_name.clone(), entry_func.entry_block)]; let entry_block = remapper.get_block(entry_func_name, entry_func.entry_block)
.ok_or_else(|| format!("Entry block not found for {}", entry_func_name))?;
if debug { if debug {
eprintln!("[cf_loop/joinir] Jumping to entry block: {:?}", entry_block); eprintln!("[cf_loop/joinir] Jumping to entry block: {:?}", entry_block);
} }
@ -945,247 +956,11 @@ impl super::MirBuilder {
Ok(()) Ok(())
} }
/// Collect all ValueIds used in a block // Phase 189: collect_values_in_block/collect_values_in_instruction removed
fn collect_values_in_block( // These functions are now provided by JoinIrIdRemapper::collect_values_in_block()
block: &crate::mir::BasicBlock,
values: &mut std::collections::BTreeSet<super::ValueId>,
) {
for inst in &block.instructions {
Self::collect_values_in_instruction(inst, values);
}
if let Some(ref term) = block.terminator {
Self::collect_values_in_instruction(term, values);
}
}
/// Collect all ValueIds used in an instruction // Phase 189: remap_joinir_instruction/remap_instruction removed
fn collect_values_in_instruction( // These functions are now provided by JoinIrIdRemapper::remap_instruction()
inst: &crate::mir::MirInstruction,
values: &mut std::collections::BTreeSet<super::ValueId>,
) {
use crate::mir::MirInstruction;
match inst {
MirInstruction::Const { dst, .. } => {
values.insert(*dst);
}
MirInstruction::BinOp { dst, lhs, rhs, .. } => {
values.insert(*dst);
values.insert(*lhs);
values.insert(*rhs);
}
MirInstruction::UnaryOp { dst, operand, .. } => {
values.insert(*dst);
values.insert(*operand);
}
MirInstruction::Compare { dst, lhs, rhs, .. } => {
values.insert(*dst);
values.insert(*lhs);
values.insert(*rhs);
}
MirInstruction::Load { dst, ptr } => {
values.insert(*dst);
values.insert(*ptr);
}
MirInstruction::Store { value, ptr } => {
values.insert(*value);
values.insert(*ptr);
}
MirInstruction::Call {
dst, func, args, ..
} => {
if let Some(d) = dst {
values.insert(*d);
}
values.insert(*func);
for arg in args {
values.insert(*arg);
}
}
MirInstruction::BoxCall {
dst, box_val, args, ..
} => {
if let Some(d) = dst {
values.insert(*d);
}
values.insert(*box_val);
for arg in args {
values.insert(*arg);
}
}
MirInstruction::Branch { condition, .. } => {
values.insert(*condition);
}
MirInstruction::Return { value } => {
if let Some(v) = value {
values.insert(*v);
}
}
MirInstruction::Phi {
dst,
inputs,
type_hint: None,
} => {
values.insert(*dst);
for (_, val) in inputs {
values.insert(*val);
}
}
MirInstruction::Copy { dst, src } => {
values.insert(*dst);
values.insert(*src);
}
MirInstruction::NewBox { dst, args, .. } => {
values.insert(*dst);
for arg in args {
values.insert(*arg);
}
}
MirInstruction::Print { value, .. } => {
values.insert(*value);
}
_ => {
// Other instructions: skip for now
}
}
}
/// Phase 189: Remap JoinIR-generated MIR instructions
///
/// For now, we use standard instruction remapping. Call instructions between
/// merged functions are preserved as Call instructions, relying on VM support
/// for handling these calls.
///
/// **Future Enhancement (Phase 189.1)**: Convert tail calls to jumps for optimization.
fn remap_joinir_instruction(
inst: &crate::mir::MirInstruction,
value_map: &std::collections::HashMap<super::ValueId, super::ValueId>,
block_map: &std::collections::HashMap<crate::mir::BasicBlockId, crate::mir::BasicBlockId>,
_function_entry_map: &std::collections::HashMap<String, crate::mir::BasicBlockId>,
_value_to_func_name: &std::collections::HashMap<super::ValueId, String>,
_debug: bool,
) -> crate::mir::MirInstruction {
// Use standard remapping
Self::remap_instruction(inst, value_map, block_map)
}
/// Remap an instruction's ValueIds and BlockIds
fn remap_instruction(
inst: &crate::mir::MirInstruction,
value_map: &std::collections::HashMap<super::ValueId, super::ValueId>,
block_map: &std::collections::HashMap<crate::mir::BasicBlockId, crate::mir::BasicBlockId>,
) -> crate::mir::MirInstruction {
use crate::mir::MirInstruction;
let remap_value = |v: super::ValueId| value_map.get(&v).copied().unwrap_or(v);
let remap_block = |b: crate::mir::BasicBlockId| block_map.get(&b).copied().unwrap_or(b);
match inst {
MirInstruction::Const { dst, value } => MirInstruction::Const {
dst: remap_value(*dst),
value: value.clone(),
},
MirInstruction::BinOp { dst, op, lhs, rhs } => MirInstruction::BinOp {
dst: remap_value(*dst),
op: *op,
lhs: remap_value(*lhs),
rhs: remap_value(*rhs),
},
MirInstruction::UnaryOp { dst, op, operand } => MirInstruction::UnaryOp {
dst: remap_value(*dst),
op: *op,
operand: remap_value(*operand),
},
MirInstruction::Compare { dst, op, lhs, rhs } => MirInstruction::Compare {
dst: remap_value(*dst),
op: *op,
lhs: remap_value(*lhs),
rhs: remap_value(*rhs),
},
MirInstruction::Load { dst, ptr } => MirInstruction::Load {
dst: remap_value(*dst),
ptr: remap_value(*ptr),
},
MirInstruction::Store { value, ptr } => MirInstruction::Store {
value: remap_value(*value),
ptr: remap_value(*ptr),
},
MirInstruction::Call {
dst,
func,
callee,
args,
effects,
} => MirInstruction::Call {
dst: dst.map(remap_value),
func: remap_value(*func),
callee: callee.clone(),
args: args.iter().map(|a| remap_value(*a)).collect(),
effects: *effects,
},
MirInstruction::BoxCall {
dst,
box_val,
method,
method_id,
args,
effects,
} => MirInstruction::BoxCall {
dst: dst.map(remap_value),
box_val: remap_value(*box_val),
method: method.clone(),
method_id: *method_id,
args: args.iter().map(|a| remap_value(*a)).collect(),
effects: *effects,
},
MirInstruction::Branch {
condition,
then_bb,
else_bb,
} => MirInstruction::Branch {
condition: remap_value(*condition),
then_bb: remap_block(*then_bb),
else_bb: remap_block(*else_bb),
},
MirInstruction::Jump { target } => MirInstruction::Jump {
target: remap_block(*target),
},
MirInstruction::Return { value } => MirInstruction::Return {
value: value.map(remap_value),
},
MirInstruction::Phi {
dst,
inputs,
type_hint: None,
} => MirInstruction::Phi {
dst: remap_value(*dst),
inputs: inputs
.iter()
.map(|(bb, val)| (remap_block(*bb), remap_value(*val)))
.collect(),
type_hint: None, // Phase 63-6: Preserve no type hint during remapping
},
MirInstruction::Copy { dst, src } => MirInstruction::Copy {
dst: remap_value(*dst),
src: remap_value(*src),
},
MirInstruction::NewBox {
dst,
box_type,
args,
} => MirInstruction::NewBox {
dst: remap_value(*dst),
box_type: box_type.clone(),
args: args.iter().map(|a| remap_value(*a)).collect(),
},
MirInstruction::Print { value, effects } => MirInstruction::Print {
value: remap_value(*value),
effects: *effects,
},
// Pass through other instructions unchanged
other => other.clone(),
}
}
/// Control-flow: try/catch/finally /// Control-flow: try/catch/finally
pub(super) fn cf_try_catch( pub(super) fn cf_try_catch(

View File

@ -1,851 +1,28 @@
use crate::ast::Span;
use crate::mir::join_ir::{ use crate::mir::join_ir::{
BinOpKind, CompareOp, ConstValue, JoinFunction, JoinInst, JoinModule, MirLikeInst, BinOpKind, CompareOp, ConstValue, JoinModule, MirLikeInst,
}; };
use crate::mir::{ use crate::mir::{
BasicBlockId, BinaryOp, CompareOp as MirCompareOp, ConstValue as MirConstValue, EffectMask, BinaryOp, CompareOp as MirCompareOp, ConstValue as MirConstValue, EffectMask, MirInstruction, MirModule,
FunctionSignature, MirFunction, MirInstruction, MirModule, MirType, ValueId,
}; };
use super::{join_func_name, JoinIrVmBridgeError}; use super::JoinIrVmBridgeError;
/// ブロックを確定するinstructions + spans + terminator を設定) // Phase 190: Use modular converters from parent module
fn finalize_block( use super::joinir_function_converter::JoinIrFunctionConverter;
mir_func: &mut MirFunction,
block_id: BasicBlockId,
instructions: Vec<MirInstruction>,
terminator: MirInstruction,
) {
if let Some(block) = mir_func.blocks.get_mut(&block_id) {
let inst_count = instructions.len();
block.instructions = instructions;
block.instruction_spans = vec![Span::unknown(); inst_count];
block.terminator = Some(terminator);
}
}
/// Phase 30.x: JoinIR → MIR 変換器 /// Phase 190: JoinIR → MIR 変換器(統合エントリーポイント)
/// ///
/// Phase 32 L-2.2 Step-3: テストから呼び出し可能に `pub(crate)` 化 /// Phase 32 L-2.2 Step-3: テストから呼び出し可能に `pub(crate)` 化
pub(crate) fn convert_joinir_to_mir( pub(crate) fn convert_joinir_to_mir(
join_module: &JoinModule, join_module: &JoinModule,
) -> Result<MirModule, JoinIrVmBridgeError> { ) -> Result<MirModule, JoinIrVmBridgeError> {
let mut mir_module = MirModule::new("joinir_bridge".to_string()); // Phase 190: Delegate to FunctionConverter
JoinIrFunctionConverter::convert_joinir_to_mir(join_module)
// Convert all JoinIR functions to MIR (entry function becomes "skip" or similar)
for (func_id, join_func) in &join_module.functions {
debug_log!(
"[joinir_vm_bridge] Converting JoinFunction {} ({})",
func_id.0,
join_func.name
);
let mir_func = convert_join_function_to_mir(join_func)?;
// Use actual function name (not "main") since we'll create a wrapper
mir_module
.functions
.insert(join_func_name(*func_id), mir_func);
}
Ok(mir_module)
} }
/// JoinFunction → MirFunction 変換
///
/// # Phase 40拡張予定: Loop Exit PHI for If-in-loop
///
/// ## Current Implementation (Phase 34)
///
/// - Header PHI: ループ開始時の変数(ループ不変変数含む)
/// - Exit PHI: ループ終了時の変数(単純パターンのみ)
///
/// ## Phase 40 Extension Required
///
/// ### Problem
///
/// 現在、if-in-loopで修正される変数のloop exit PHIが生成されない。
///
/// ```nyash,ignore
/// local out = new ArrayBox()
/// loop(i < n) {
/// if fn(arr[i]) { out.push(arr[i]) } // ← out修正
/// i = i + 1
/// }
/// // Missing: phi out_exit = (out_header, out_if_modified)
/// ```
///
/// ### Solution (Phase 40-1)
///
/// JoinIR Frontend AST loweringで検出したif-in-loop修正変数を
/// JoinModule metadataに格納し、MIR loweringで読み取る。
///
/// ### Implementation Plan
///
/// 1. JoinModule metadataに`if_in_loop_modified_vars: HashSet<String>`追加
/// 2. AST lowering時に`extract_if_in_loop_modified_vars()`結果をmetadataに格納
/// 3. MIR lowering時にmetadataから読み取り、loop exit PHI生成
///
/// ### Code Location
///
/// この関数内で以下を追加:
///
/// ```rust,ignore
/// // TODO(Phase 40-1): Generate loop exit PHI for if-in-loop modified variables
/// if let Some(modified_vars) = join_func.metadata.get("if_in_loop_modified_vars") {
/// for var_name in modified_vars.as_array().unwrap() {
/// let var_name_str = var_name.as_str().unwrap();
///
/// // Get header value (loop entry)
/// let header_value = self.get_var_value_at_header(var_name_str);
///
/// // Get exit value (loop body last modification)
/// let exit_value = self.get_var_value_at_exit(var_name_str);
///
/// // Emit PHI at loop exit block
/// self.emit_phi(
/// exit_block_id,
/// var_name_str,
/// vec![header_value, exit_value],
/// );
/// }
/// }
/// ```
///
/// ### Example (array_ext.filter)
///
/// ```nyash,ignore
/// // Input AST
/// local out = new ArrayBox()
/// local i = 0
/// loop(i < arr.len()) {
/// if fn(arr[i]) { out.push(arr[i]) } // out modified in if
/// i = i + 1
/// }
/// return out
///
/// // JoinIR (Phase 40)
/// entry():
/// out_init = new ArrayBox
/// i_init = 0
/// call loop_step(i_init, out_init, arr)
///
/// loop_step(i, out, arr):
/// exit_cond = i >= arr.len()
/// jump k_exit(out) if exit_cond // ← out needs PHI at k_exit
/// elem = arr[i]
/// should_push = fn(elem)
/// out_next = select(should_push, out.push(elem), out) // conditional modification
/// i_next = i + 1
/// call loop_step(i_next, out_next, arr)
///
/// k_exit(out_final):
/// ret out_final
///
/// // MIR (Phase 40)
/// // At loop exit block:
/// %out_exit = phi [%out_init, entry], [%out_next, loop_step] // ← Phase 40で生成
/// ```
///
/// # See Also
///
/// - AST lowering: `ast_lowerer.rs::extract_if_in_loop_modified_vars()`
/// - Design: `docs/.../phase-39-if-phi-level2/joinir_extension_design.md`
pub(crate) fn convert_join_function_to_mir(
join_func: &JoinFunction,
) -> Result<MirFunction, JoinIrVmBridgeError> {
// TODO(Phase 40-1): Generate loop exit PHI for if-in-loop modified variables
// See comment above for implementation details
// Integration point: After loop body lowering, before exit block finalization
// Phase 27-shortterm S-4.4: skip_ws パターン対応版
// - Call (tail call): MIR Call に変換
// - Jump (conditional exit): Branch + Return に変換
let entry_block = BasicBlockId(0);
// Create minimal FunctionSignature for JoinIR function
// Phase 27-shortterm: すべて MirType::Unknown として扱う(型情報は JoinIR に無いため)
let param_types = join_func
.params
.iter()
.map(|_| MirType::Unknown)
.collect::<Vec<_>>();
let signature = FunctionSignature {
name: join_func.name.clone(),
params: param_types,
return_type: MirType::Unknown,
effects: EffectMask::PURE,
};
let mut mir_func = MirFunction::new(signature, entry_block);
// Phase 30.x: Set parameter ValueIds from JoinIR function
// JoinIR's VarId is an alias for ValueId, so direct copy works
mir_func.params = join_func.params.clone();
// Phase 27-shortterm S-4.4: Multi-block conversion for Jump instructions
// Strategy:
// - Accumulate Compute instructions in current block
// - On Jump: emit Branch + create exit block with Return
// - On Call: emit Call in current block
let mut current_block_id = entry_block;
let mut current_instructions = Vec::new();
let mut next_block_id = 1u32; // for creating new blocks
for join_inst in &join_func.body {
match join_inst {
JoinInst::Compute(mir_like) => {
let mir_inst = convert_mir_like_inst(mir_like)?;
current_instructions.push(mir_inst);
}
JoinInst::MethodCall {
dst,
receiver,
method,
args,
type_hint, // Phase 65-2-A: 型ヒント追加現状は無視、Phase 65-3 で活用)
} => {
// Phase 34-6: MethodCall → MIR BoxCall 変換
// receiver.method(args...) を BoxCall(receiver, method, args) に変換
let mir_inst = MirInstruction::BoxCall {
dst: Some(*dst),
box_val: *receiver,
method: method.clone(),
method_id: None,
args: args.clone(),
effects: EffectMask::PURE,
};
current_instructions.push(mir_inst);
// Phase 65-2-A: TODO: type_hint を value_types に記録する処理を Phase 65-3 で追加
let _ = type_hint; // 現状は unused warning 回避
}
// Phase 56: ConditionalMethodCall → MIR (cond ? method : no-op)
JoinInst::ConditionalMethodCall {
cond,
dst,
receiver,
method,
args,
} => {
// Phase 56: ConditionalMethodCall を MIR の if/phi に変換
// cond が true の場合: receiver.method(args) → dst
// cond が false の場合: receiver → dst (変更なし)
//
// 4 ブロック構造: cond -> then/else -> merge
debug_log!(
"[joinir_vm_bridge] Converting ConditionalMethodCall: dst={:?}, cond={:?}, receiver={:?}, method={}",
dst, cond, receiver, method
);
// 1. cond ブロック(現在のブロック)
let cond_block = current_block_id;
// 2. then ブロック作成
let then_block = BasicBlockId(next_block_id);
next_block_id += 1;
// 3. else ブロック作成
let else_block = BasicBlockId(next_block_id);
next_block_id += 1;
// 4. merge ブロック作成
let merge_block = BasicBlockId(next_block_id);
next_block_id += 1;
// 5. cond ブロックで分岐
let branch_terminator = MirInstruction::Branch {
condition: *cond,
then_bb: then_block,
else_bb: else_block,
};
finalize_block(
&mut mir_func,
cond_block,
current_instructions,
branch_terminator,
);
// 6. then ブロック: dst = receiver.method(args); jump merge
let mut then_block_obj = crate::mir::BasicBlock::new(then_block);
then_block_obj.instructions.push(MirInstruction::BoxCall {
dst: Some(*dst),
box_val: *receiver,
method: method.clone(),
method_id: None,
args: args.clone(),
effects: EffectMask::PURE,
});
then_block_obj.instruction_spans.push(Span::unknown());
then_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(then_block, then_block_obj);
// 7. else ブロック: dst = receiver (no-op, keep original); jump merge
let mut else_block_obj = crate::mir::BasicBlock::new(else_block);
else_block_obj.instructions.push(MirInstruction::Copy {
dst: *dst,
src: *receiver,
});
else_block_obj.instruction_spans.push(Span::unknown());
else_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(else_block, else_block_obj);
// 8. merge ブロック作成(空)
let merge_block_obj = crate::mir::BasicBlock::new(merge_block);
mir_func.blocks.insert(merge_block, merge_block_obj);
// 9. merge ブロックに移動
current_block_id = merge_block;
current_instructions = Vec::new();
}
// Phase 51: FieldAccess → MIR BoxCall (getter pattern)
JoinInst::FieldAccess { dst, object, field } => {
// object.field を BoxCall(object, field, []) に変換
// フィールドアクセスはメソッド呼び出しとして扱うgetter pattern
let mir_inst = MirInstruction::BoxCall {
dst: Some(*dst),
box_val: *object,
method: field.clone(),
method_id: None,
args: vec![],
effects: EffectMask::PURE,
};
current_instructions.push(mir_inst);
}
// Phase 51: NewBox → MIR NewBox
JoinInst::NewBox {
dst,
box_name,
args,
type_hint, // Phase 65-2-B: 型ヒント追加現状は無視、Phase 65-3 で活用)
} => {
let mir_inst = MirInstruction::NewBox {
dst: *dst,
box_type: box_name.clone(),
args: args.clone(),
};
current_instructions.push(mir_inst);
// Phase 65-2-B: TODO: type_hint を value_types に記録する処理を Phase 65-3 で追加
let _ = type_hint; // 現状は unused warning 回避
}
JoinInst::Call {
func,
args,
dst,
k_next,
} => {
// Phase 30.x: Support both tail calls and non-tail calls
// - dst=None, k_next=None: Tail call → call + return
// - dst=Some(id), k_next=None: Non-tail call → call + store + continue
// - k_next=Some: Not yet supported
if k_next.is_some() {
let call_target_name = join_func_name(*func);
return Err(JoinIrVmBridgeError::new(format!(
"Call with k_next is not yet supported\n\
\n\
Current function: {}\n\
Call target: {} (JoinFuncId: {:?})\n\
Arguments: {} args\n\
k_next: {:?}\n\
\n\
💡 Fix: Change `k_next: Some(...)` to `k_next: None`\n\
💡 Note: Phase 31 and Phase 34 both use k_next=None (bridge limitation)\n\
\n\
Example:\n\
Call {{\n\
func: loop_step_id,\n\
args: vec![i_next, acc_next, n],\n\
k_next: None, // ⚠️ Must be None\n\
dst: Some(result),\n\
}}",
join_func.name,
call_target_name,
func,
args.len(),
k_next,
)));
}
// Convert JoinFuncId to function name
let func_name = join_func_name(*func);
// Create temporary ValueId for function name
let func_name_id = ValueId(99990 + next_block_id);
next_block_id += 1;
// Add Const instruction for function name
current_instructions.push(MirInstruction::Const {
dst: func_name_id,
value: MirConstValue::String(func_name),
});
match dst {
Some(result_dst) => {
// Non-tail call: store result in dst and continue
current_instructions.push(MirInstruction::Call {
dst: Some(*result_dst),
func: func_name_id,
callee: None,
args: args.clone(),
effects: EffectMask::PURE,
});
// Continue to next instruction (no block termination)
}
None => {
// Tail call: call + return result
let call_result_id = ValueId(99991);
current_instructions.push(MirInstruction::Call {
dst: Some(call_result_id),
func: func_name_id,
callee: None,
args: args.clone(),
effects: EffectMask::PURE,
});
// Return the result of the tail call
let terminator = MirInstruction::Return {
value: Some(call_result_id),
};
finalize_block(
&mut mir_func,
current_block_id,
current_instructions,
terminator,
);
current_instructions = Vec::new();
}
}
}
JoinInst::Jump {
cont: _,
args,
cond,
} => {
// Phase 27-shortterm S-4.4-A: Jump with condition → Branch + Return
// Jump represents an exit continuation (k_exit) in skip_ws pattern
debug_log!(
"[joinir_vm_bridge] Converting Jump args={:?}, cond={:?}",
args,
cond
);
match cond {
Some(cond_var) => {
// Conditional jump: Branch to exit block
let exit_block_id = BasicBlockId(next_block_id);
next_block_id += 1;
let continue_block_id = BasicBlockId(next_block_id);
next_block_id += 1;
// Phase 30.x: Branch terminator (separate from instructions)
let branch_terminator = MirInstruction::Branch {
condition: *cond_var,
then_bb: exit_block_id,
else_bb: continue_block_id,
};
// Finalize current block with Branch terminator
finalize_block(
&mut mir_func,
current_block_id,
current_instructions,
branch_terminator,
);
// Create exit block with Return terminator
let exit_value = args.first().copied();
let mut exit_block = crate::mir::BasicBlock::new(exit_block_id);
exit_block.terminator = Some(MirInstruction::Return { value: exit_value });
mir_func.blocks.insert(exit_block_id, exit_block);
// Create continue block (will be populated by subsequent instructions)
let continue_block = crate::mir::BasicBlock::new(continue_block_id);
mir_func.blocks.insert(continue_block_id, continue_block);
// Continue in the next block
current_block_id = continue_block_id;
current_instructions = Vec::new();
}
None => {
// Unconditional jump: direct Return terminator
let exit_value = args.first().copied();
let return_terminator = MirInstruction::Return { value: exit_value };
// Finalize current block with Return terminator
finalize_block(
&mut mir_func,
current_block_id,
current_instructions,
return_terminator,
);
// No continuation after unconditional return
current_instructions = Vec::new();
}
}
}
// Phase 33: Select instruction conversion to MIR
JoinInst::Select {
dst,
cond,
then_val,
else_val,
type_hint, // Phase 63-6: Type hint propagated to MIR Phi
} => {
// Phase 33-2: Select を MIR の if/phi に変換
// Phase 63-6: PHI instruction with type hint from JoinIR
debug_log!(
"[joinir_vm_bridge] Converting Select: dst={:?}, cond={:?}, then={:?}, else={:?}, type_hint={:?}",
dst,
cond,
then_val,
else_val,
type_hint
);
// 1. cond ブロック(現在のブロック)
let cond_block = current_block_id;
// 2. then ブロック作成
let then_block = BasicBlockId(next_block_id);
next_block_id += 1;
// 3. else ブロック作成
let else_block = BasicBlockId(next_block_id);
next_block_id += 1;
// 4. merge ブロック作成
let merge_block = BasicBlockId(next_block_id);
next_block_id += 1;
// 5. cond ブロックで分岐
let branch_terminator = MirInstruction::Branch {
condition: *cond,
then_bb: then_block,
else_bb: else_block,
};
finalize_block(
&mut mir_func,
cond_block,
current_instructions,
branch_terminator,
);
// 6. then ブロック: jump merge (no Copy, PHI will handle it)
let mut then_block_obj = crate::mir::BasicBlock::new(then_block);
then_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(then_block, then_block_obj);
// 7. else ブロック: jump merge (no Copy, PHI will handle it)
let mut else_block_obj = crate::mir::BasicBlock::new(else_block);
else_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(else_block, else_block_obj);
// 8. merge ブロック: PHI instruction with type hint
let mut merge_block_obj = crate::mir::BasicBlock::new(merge_block);
// Phase 63-6: Create PHI with type hint from JoinIR Select
merge_block_obj.instructions.push(MirInstruction::Phi {
dst: *dst,
inputs: vec![(then_block, *then_val), (else_block, *else_val)],
type_hint: type_hint.clone(), // Phase 63-6: Propagate type hint from JoinIR
});
merge_block_obj.instruction_spans.push(Span::unknown());
mir_func.blocks.insert(merge_block, merge_block_obj);
// 9. merge ブロックに移動
current_block_id = merge_block;
current_instructions = Vec::new();
}
// Phase 33-6: IfMerge instruction conversion to MIR
JoinInst::IfMerge {
cond,
merges,
k_next,
} => {
// Phase 33-6: IfMerge を MIR の if/phi に変換
// Select と同じ 4 ブロック構造だが、複数の Copy を生成
// Phase 33-6 最小実装: k_next は None のみサポート
if k_next.is_some() {
return Err(JoinIrVmBridgeError::new(
"IfMerge: k_next continuation is not yet supported (Phase 33-6 minimal)"
.to_string(),
));
}
debug_log!(
"[joinir_vm_bridge] Converting IfMerge: cond={:?}, merges.len()={}",
cond,
merges.len()
);
// 1. cond ブロック(現在のブロック)
let cond_block = current_block_id;
// 2. then ブロック作成
let then_block = BasicBlockId(next_block_id);
next_block_id += 1;
// 3. else ブロック作成
let else_block = BasicBlockId(next_block_id);
next_block_id += 1;
// 4. merge ブロック作成
let merge_block = BasicBlockId(next_block_id);
next_block_id += 1;
// 5. cond ブロックで分岐
let branch_terminator = MirInstruction::Branch {
condition: *cond,
then_bb: then_block,
else_bb: else_block,
};
finalize_block(
&mut mir_func,
cond_block,
current_instructions,
branch_terminator,
);
// 6. then ブロック: 各 merge について dst = then_val; jump merge
let mut then_block_obj = crate::mir::BasicBlock::new(then_block);
for merge in merges {
then_block_obj.instructions.push(MirInstruction::Copy {
dst: merge.dst,
src: merge.then_val,
});
then_block_obj.instruction_spans.push(Span::unknown());
}
then_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(then_block, then_block_obj);
// 7. else ブロック: 各 merge について dst = else_val; jump merge
let mut else_block_obj = crate::mir::BasicBlock::new(else_block);
for merge in merges {
else_block_obj.instructions.push(MirInstruction::Copy {
dst: merge.dst,
src: merge.else_val,
});
else_block_obj.instruction_spans.push(Span::unknown());
}
else_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(else_block, else_block_obj);
// 8. merge ブロック作成(空)
let merge_block_obj = crate::mir::BasicBlock::new(merge_block);
mir_func.blocks.insert(merge_block, merge_block_obj);
// 9. merge ブロックに移動
current_block_id = merge_block;
current_instructions = Vec::new();
}
JoinInst::Ret { value } => {
// Phase 30.x: Return terminator (separate from instructions)
let return_terminator = MirInstruction::Return { value: *value };
// Finalize current block with Return terminator
finalize_block(
&mut mir_func,
current_block_id,
current_instructions,
return_terminator,
);
current_instructions = Vec::new();
}
// Phase 41-4: NestedIfMerge instruction
JoinInst::NestedIfMerge {
conds,
merges,
k_next,
} => {
// Phase 41-4.3: 多段 Branch + PHI を生成
//
// 構造:
// cond_block: branch cond[0] -> level_1_block, final_else_block
// level_1_block: branch cond[1] -> level_2_block, final_else_block
// ...
// level_n_block: branch cond[n] -> then_block, final_else_block
// then_block: Copy dst=then_val; jump merge_block
// final_else_block: Copy dst=else_val; jump merge_block
// merge_block: (continue)
// k_next は None のみサポートPhase 41-4.3 最小実装)
if k_next.is_some() {
return Err(JoinIrVmBridgeError::new(
"NestedIfMerge: k_next continuation is not yet supported".to_string(),
));
}
if conds.is_empty() {
return Err(JoinIrVmBridgeError::new(
"NestedIfMerge: conds must not be empty".to_string(),
));
}
debug_log!(
"[joinir_vm_bridge] Converting NestedIfMerge: conds.len()={}, merges.len()={}",
conds.len(),
merges.len()
);
// 1. ブロックを事前確保
// - 各条件レベルに 1 ブロック(現在のブロック + 追加分)
// - then_block
// - final_else_block
// - merge_block
let num_conds = conds.len();
// level blocks: conds[0] は current_block で処理、conds[1..] は新規ブロック
let mut level_blocks: Vec<BasicBlockId> = Vec::with_capacity(num_conds);
level_blocks.push(current_block_id); // level 0 = current block
for _ in 1..num_conds {
level_blocks.push(BasicBlockId(next_block_id));
next_block_id += 1;
}
let then_block = BasicBlockId(next_block_id);
next_block_id += 1;
let final_else_block = BasicBlockId(next_block_id);
next_block_id += 1;
let merge_block = BasicBlockId(next_block_id);
next_block_id += 1;
// 2. level 1+ ブロックを事前作成finalize_block は既存ブロックのみ更新)
for level in 1..num_conds {
let level_block = level_blocks[level];
mir_func
.blocks
.insert(level_block, crate::mir::BasicBlock::new(level_block));
}
// 3. 各レベルで分岐を生成
for (level, cond_var) in conds.iter().enumerate() {
let this_block = level_blocks[level];
// 次のレベルまたは then_block への分岐先
let next_true_block = if level + 1 < num_conds {
level_blocks[level + 1]
} else {
then_block
};
// false の場合は常に final_else_block へ
let branch_terminator = MirInstruction::Branch {
condition: *cond_var,
then_bb: next_true_block,
else_bb: final_else_block,
};
if level == 0 {
// level 0 は current_block、current_instructions を使う
finalize_block(
&mut mir_func,
this_block,
current_instructions.clone(),
branch_terminator,
);
current_instructions.clear();
} else {
// level 1+ は事前作成済みブロックを更新
finalize_block(&mut mir_func, this_block, Vec::new(), branch_terminator);
}
}
// 3. then_block: 全条件 true の場合 → then_val を Copy
let mut then_block_obj = crate::mir::BasicBlock::new(then_block);
for merge in merges {
then_block_obj.instructions.push(MirInstruction::Copy {
dst: merge.dst,
src: merge.then_val,
});
then_block_obj.instruction_spans.push(Span::unknown());
}
then_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(then_block, then_block_obj);
// 4. final_else_block: いずれかの条件 false の場合 → else_val を Copy
let mut else_block_obj = crate::mir::BasicBlock::new(final_else_block);
for merge in merges {
else_block_obj.instructions.push(MirInstruction::Copy {
dst: merge.dst,
src: merge.else_val,
});
else_block_obj.instruction_spans.push(Span::unknown());
}
else_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(final_else_block, else_block_obj);
// 5. merge_block
let merge_block_obj = crate::mir::BasicBlock::new(merge_block);
mir_func.blocks.insert(merge_block, merge_block_obj);
// 6. merge_block に移動して継続
current_block_id = merge_block;
current_instructions = Vec::new();
}
}
}
// Finalize any remaining instructions in the last block
if !current_instructions.is_empty() {
debug_log!(
"[joinir_vm_bridge] Final block {:?} has {} remaining instructions",
current_block_id,
current_instructions.len()
);
if let Some(block) = mir_func.blocks.get_mut(&current_block_id) {
// Phase 30.x: VM requires instruction_spans to match instructions length
let inst_count = current_instructions.len();
block.instructions = current_instructions;
block.instruction_spans = vec![Span::unknown(); inst_count];
}
}
// Debug: print all blocks and their instruction counts + terminators
debug_log!(
"[joinir_vm_bridge] Function '{}' has {} blocks:",
mir_func.signature.name,
mir_func.blocks.len()
);
for (block_id, block) in &mir_func.blocks {
debug_log!(
" Block {:?}: {} instructions, terminator={:?}",
block_id,
block.instructions.len(),
block.terminator
);
}
Ok(mir_func)
}
/// MirLikeInst → MirInstruction 変換 /// MirLikeInst → MirInstruction 変換
/// Phase 190: 共有ユーティリティとして pub(crate) に変更
pub(crate) fn convert_mir_like_inst( pub(crate) fn convert_mir_like_inst(
mir_like: &MirLikeInst, mir_like: &MirLikeInst,
) -> Result<MirInstruction, JoinIrVmBridgeError> { ) -> Result<MirInstruction, JoinIrVmBridgeError> {

View File

@ -0,0 +1,691 @@
//! Phase 190: JoinIR Block Converter
//!
//! 責務: JoinIR のブロックを MIR ブロックに変換
//! - 命令列変換
//! - ターミネータJump/Branch/Returnの処理
//! - ブロックID マッピング管理
use crate::ast::Span;
use crate::mir::join_ir::{JoinInst, MirLikeInst};
use crate::mir::{BasicBlockId, EffectMask, MirFunction, MirInstruction, ValueId};
use super::{convert_mir_like_inst, join_func_name, JoinIrVmBridgeError};
pub struct JoinIrBlockConverter {
current_block_id: BasicBlockId,
current_instructions: Vec<MirInstruction>,
next_block_id: u32,
}
impl JoinIrBlockConverter {
pub fn new() -> Self {
Self {
current_block_id: BasicBlockId(0), // entry block
current_instructions: Vec::new(),
next_block_id: 1, // start from 1 (0 is entry)
}
}
/// JoinIR 関数本体を MIR ブロック群に変換
///
/// # Phase 27-shortterm S-4.4: Multi-block conversion
///
/// Strategy:
/// - Accumulate Compute instructions in current block
/// - On Jump: emit Branch + create exit block with Return
/// - On Call: emit Call in current block
pub fn convert_function_body(
&mut self,
mir_func: &mut MirFunction,
join_body: &[JoinInst],
) -> Result<(), JoinIrVmBridgeError> {
for join_inst in join_body {
match join_inst {
JoinInst::Compute(mir_like) => {
let mir_inst = convert_mir_like_inst(mir_like)?;
self.current_instructions.push(mir_inst);
}
JoinInst::MethodCall {
dst,
receiver,
method,
args,
type_hint,
} => {
self.handle_method_call(dst, receiver, method, args, type_hint)?;
}
JoinInst::ConditionalMethodCall {
cond,
dst,
receiver,
method,
args,
} => {
self.handle_conditional_method_call(mir_func, cond, dst, receiver, method, args)?;
}
JoinInst::FieldAccess { dst, object, field } => {
self.handle_field_access(dst, object, field)?;
}
JoinInst::NewBox {
dst,
box_name,
args,
type_hint,
} => {
self.handle_new_box(dst, box_name, args, type_hint)?;
}
JoinInst::Call {
func,
args,
dst,
k_next,
} => {
self.handle_call(mir_func, func, args, dst, k_next)?;
}
JoinInst::Jump { cont, args, cond } => {
self.handle_jump(mir_func, cont, args, cond)?;
}
JoinInst::Select {
dst,
cond,
then_val,
else_val,
type_hint,
} => {
self.handle_select(mir_func, dst, cond, then_val, else_val, type_hint)?;
}
JoinInst::IfMerge {
cond,
merges,
k_next,
} => {
self.handle_if_merge(mir_func, cond, merges, k_next)?;
}
JoinInst::Ret { value } => {
self.handle_ret(mir_func, value)?;
}
JoinInst::NestedIfMerge {
conds,
merges,
k_next,
} => {
self.handle_nested_if_merge(mir_func, conds, merges, k_next)?;
}
}
}
// Finalize any remaining instructions
self.finalize_remaining_instructions(mir_func);
Ok(())
}
// === Instruction Handlers ===
fn handle_method_call(
&mut self,
dst: &ValueId,
receiver: &ValueId,
method: &str,
args: &[ValueId],
type_hint: &Option<crate::mir::MirType>,
) -> Result<(), JoinIrVmBridgeError> {
let mir_inst = MirInstruction::BoxCall {
dst: Some(*dst),
box_val: *receiver,
method: method.to_string(),
method_id: None,
args: args.to_vec(),
effects: EffectMask::PURE,
};
self.current_instructions.push(mir_inst);
// Phase 65-2-A: TODO: type_hint を value_types に記録
let _ = type_hint;
Ok(())
}
fn handle_conditional_method_call(
&mut self,
mir_func: &mut MirFunction,
cond: &ValueId,
dst: &ValueId,
receiver: &ValueId,
method: &str,
args: &[ValueId],
) -> Result<(), JoinIrVmBridgeError> {
// Phase 56: ConditionalMethodCall を if/phi に変換
debug_log!(
"[joinir_block] Converting ConditionalMethodCall: dst={:?}, cond={:?}",
dst,
cond
);
let cond_block = self.current_block_id;
let then_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
let else_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
let merge_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
// cond block: branch
let branch_terminator = MirInstruction::Branch {
condition: *cond,
then_bb: then_block,
else_bb: else_block,
};
Self::finalize_block(
mir_func,
cond_block,
std::mem::take(&mut self.current_instructions),
branch_terminator,
);
// then block: method call
let mut then_block_obj = crate::mir::BasicBlock::new(then_block);
then_block_obj.instructions.push(MirInstruction::BoxCall {
dst: Some(*dst),
box_val: *receiver,
method: method.to_string(),
method_id: None,
args: args.to_vec(),
effects: EffectMask::PURE,
});
then_block_obj.instruction_spans.push(Span::unknown());
then_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(then_block, then_block_obj);
// else block: copy receiver
let mut else_block_obj = crate::mir::BasicBlock::new(else_block);
else_block_obj.instructions.push(MirInstruction::Copy {
dst: *dst,
src: *receiver,
});
else_block_obj.instruction_spans.push(Span::unknown());
else_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(else_block, else_block_obj);
// merge block
let merge_block_obj = crate::mir::BasicBlock::new(merge_block);
mir_func.blocks.insert(merge_block, merge_block_obj);
self.current_block_id = merge_block;
Ok(())
}
fn handle_field_access(
&mut self,
dst: &ValueId,
object: &ValueId,
field: &str,
) -> Result<(), JoinIrVmBridgeError> {
// Phase 51: FieldAccess → BoxCall (getter pattern)
let mir_inst = MirInstruction::BoxCall {
dst: Some(*dst),
box_val: *object,
method: field.to_string(),
method_id: None,
args: vec![],
effects: EffectMask::PURE,
};
self.current_instructions.push(mir_inst);
Ok(())
}
fn handle_new_box(
&mut self,
dst: &ValueId,
box_name: &str,
args: &[ValueId],
type_hint: &Option<crate::mir::MirType>,
) -> Result<(), JoinIrVmBridgeError> {
let mir_inst = MirInstruction::NewBox {
dst: *dst,
box_type: box_name.to_string(),
args: args.to_vec(),
};
self.current_instructions.push(mir_inst);
// Phase 65-2-B: TODO: type_hint を value_types に記録
let _ = type_hint;
Ok(())
}
fn handle_call(
&mut self,
mir_func: &mut MirFunction,
func: &crate::mir::join_ir::JoinFuncId,
args: &[ValueId],
dst: &Option<ValueId>,
k_next: &Option<crate::mir::join_ir::JoinContId>,
) -> Result<(), JoinIrVmBridgeError> {
// Phase 30.x: Call conversion
if k_next.is_some() {
return Err(JoinIrVmBridgeError::new(
"Call with k_next is not yet supported".to_string(),
));
}
let func_name = join_func_name(*func);
let func_name_id = ValueId(99990 + self.next_block_id);
self.next_block_id += 1;
self.current_instructions.push(MirInstruction::Const {
dst: func_name_id,
value: crate::mir::ConstValue::String(func_name),
});
match dst {
Some(result_dst) => {
// Non-tail call
self.current_instructions.push(MirInstruction::Call {
dst: Some(*result_dst),
func: func_name_id,
callee: None,
args: args.to_vec(),
effects: EffectMask::PURE,
});
}
None => {
// Tail call
let call_result_id = ValueId(99991);
self.current_instructions.push(MirInstruction::Call {
dst: Some(call_result_id),
func: func_name_id,
callee: None,
args: args.to_vec(),
effects: EffectMask::PURE,
});
let terminator = MirInstruction::Return {
value: Some(call_result_id),
};
Self::finalize_block(
mir_func,
self.current_block_id,
std::mem::take(&mut self.current_instructions),
terminator,
);
}
}
Ok(())
}
fn handle_jump(
&mut self,
mir_func: &mut MirFunction,
_cont: &crate::mir::join_ir::JoinContId,
args: &[ValueId],
cond: &Option<ValueId>,
) -> Result<(), JoinIrVmBridgeError> {
// Phase 27-shortterm S-4.4-A: Jump → Branch/Return
debug_log!(
"[joinir_block] Converting Jump args={:?}, cond={:?}",
args,
cond
);
match cond {
Some(cond_var) => {
// Conditional jump
let exit_block_id = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
let continue_block_id = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
let branch_terminator = MirInstruction::Branch {
condition: *cond_var,
then_bb: exit_block_id,
else_bb: continue_block_id,
};
Self::finalize_block(
mir_func,
self.current_block_id,
std::mem::take(&mut self.current_instructions),
branch_terminator,
);
// Exit block
let exit_value = args.first().copied();
let mut exit_block = crate::mir::BasicBlock::new(exit_block_id);
exit_block.terminator = Some(MirInstruction::Return { value: exit_value });
mir_func.blocks.insert(exit_block_id, exit_block);
// Continue block
let continue_block = crate::mir::BasicBlock::new(continue_block_id);
mir_func.blocks.insert(continue_block_id, continue_block);
self.current_block_id = continue_block_id;
}
None => {
// Unconditional jump
let exit_value = args.first().copied();
let return_terminator = MirInstruction::Return { value: exit_value };
Self::finalize_block(
mir_func,
self.current_block_id,
std::mem::take(&mut self.current_instructions),
return_terminator,
);
}
}
Ok(())
}
fn handle_select(
&mut self,
mir_func: &mut MirFunction,
dst: &ValueId,
cond: &ValueId,
then_val: &ValueId,
else_val: &ValueId,
type_hint: &Option<crate::mir::MirType>,
) -> Result<(), JoinIrVmBridgeError> {
// Phase 33-2: Select → if/phi
debug_log!(
"[joinir_block] Converting Select: dst={:?}, type_hint={:?}",
dst,
type_hint
);
let cond_block = self.current_block_id;
let then_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
let else_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
let merge_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
// cond block: branch
let branch_terminator = MirInstruction::Branch {
condition: *cond,
then_bb: then_block,
else_bb: else_block,
};
Self::finalize_block(
mir_func,
cond_block,
std::mem::take(&mut self.current_instructions),
branch_terminator,
);
// then/else blocks
let mut then_block_obj = crate::mir::BasicBlock::new(then_block);
then_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(then_block, then_block_obj);
let mut else_block_obj = crate::mir::BasicBlock::new(else_block);
else_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(else_block, else_block_obj);
// merge block: PHI
let mut merge_block_obj = crate::mir::BasicBlock::new(merge_block);
merge_block_obj.instructions.push(MirInstruction::Phi {
dst: *dst,
inputs: vec![(then_block, *then_val), (else_block, *else_val)],
type_hint: type_hint.clone(),
});
merge_block_obj.instruction_spans.push(Span::unknown());
mir_func.blocks.insert(merge_block, merge_block_obj);
self.current_block_id = merge_block;
Ok(())
}
fn handle_if_merge(
&mut self,
mir_func: &mut MirFunction,
cond: &ValueId,
merges: &[crate::mir::join_ir::MergePair],
k_next: &Option<crate::mir::join_ir::JoinContId>,
) -> Result<(), JoinIrVmBridgeError> {
// Phase 33-6: IfMerge → if/phi (multiple variables)
if k_next.is_some() {
return Err(JoinIrVmBridgeError::new(
"IfMerge: k_next not yet supported".to_string(),
));
}
debug_log!(
"[joinir_block] Converting IfMerge: merges.len()={}",
merges.len()
);
let cond_block = self.current_block_id;
let then_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
let else_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
let merge_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
// cond block: branch
let branch_terminator = MirInstruction::Branch {
condition: *cond,
then_bb: then_block,
else_bb: else_block,
};
Self::finalize_block(
mir_func,
cond_block,
std::mem::take(&mut self.current_instructions),
branch_terminator,
);
// then block: copy then_val
let mut then_block_obj = crate::mir::BasicBlock::new(then_block);
for merge in merges {
then_block_obj.instructions.push(MirInstruction::Copy {
dst: merge.dst,
src: merge.then_val,
});
then_block_obj.instruction_spans.push(Span::unknown());
}
then_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(then_block, then_block_obj);
// else block: copy else_val
let mut else_block_obj = crate::mir::BasicBlock::new(else_block);
for merge in merges {
else_block_obj.instructions.push(MirInstruction::Copy {
dst: merge.dst,
src: merge.else_val,
});
else_block_obj.instruction_spans.push(Span::unknown());
}
else_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(else_block, else_block_obj);
// merge block
let merge_block_obj = crate::mir::BasicBlock::new(merge_block);
mir_func.blocks.insert(merge_block, merge_block_obj);
self.current_block_id = merge_block;
Ok(())
}
fn handle_ret(
&mut self,
mir_func: &mut MirFunction,
value: &Option<ValueId>,
) -> Result<(), JoinIrVmBridgeError> {
let return_terminator = MirInstruction::Return { value: *value };
Self::finalize_block(
mir_func,
self.current_block_id,
std::mem::take(&mut self.current_instructions),
return_terminator,
);
Ok(())
}
fn handle_nested_if_merge(
&mut self,
mir_func: &mut MirFunction,
conds: &[ValueId],
merges: &[crate::mir::join_ir::MergePair],
k_next: &Option<crate::mir::join_ir::JoinContId>,
) -> Result<(), JoinIrVmBridgeError> {
// Phase 41-4: NestedIfMerge → multi-level Branch + PHI
if k_next.is_some() {
return Err(JoinIrVmBridgeError::new(
"NestedIfMerge: k_next not yet supported".to_string(),
));
}
if conds.is_empty() {
return Err(JoinIrVmBridgeError::new(
"NestedIfMerge: conds must not be empty".to_string(),
));
}
debug_log!(
"[joinir_block] Converting NestedIfMerge: conds.len()={}",
conds.len()
);
let num_conds = conds.len();
let mut level_blocks: Vec<BasicBlockId> = Vec::with_capacity(num_conds);
level_blocks.push(self.current_block_id);
for _ in 1..num_conds {
level_blocks.push(BasicBlockId(self.next_block_id));
self.next_block_id += 1;
}
let then_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
let final_else_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
let merge_block = BasicBlockId(self.next_block_id);
self.next_block_id += 1;
// Pre-create level 1+ blocks
for level in 1..num_conds {
mir_func.blocks.insert(
level_blocks[level],
crate::mir::BasicBlock::new(level_blocks[level]),
);
}
// Create branches
for (level, cond_var) in conds.iter().enumerate() {
let this_block = level_blocks[level];
let next_true_block = if level + 1 < num_conds {
level_blocks[level + 1]
} else {
then_block
};
let branch_terminator = MirInstruction::Branch {
condition: *cond_var,
then_bb: next_true_block,
else_bb: final_else_block,
};
if level == 0 {
Self::finalize_block(
mir_func,
this_block,
std::mem::take(&mut self.current_instructions),
branch_terminator,
);
} else {
Self::finalize_block(mir_func, this_block, Vec::new(), branch_terminator);
}
}
// then block
let mut then_block_obj = crate::mir::BasicBlock::new(then_block);
for merge in merges {
then_block_obj.instructions.push(MirInstruction::Copy {
dst: merge.dst,
src: merge.then_val,
});
then_block_obj.instruction_spans.push(Span::unknown());
}
then_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(then_block, then_block_obj);
// else block
let mut else_block_obj = crate::mir::BasicBlock::new(final_else_block);
for merge in merges {
else_block_obj.instructions.push(MirInstruction::Copy {
dst: merge.dst,
src: merge.else_val,
});
else_block_obj.instruction_spans.push(Span::unknown());
}
else_block_obj.terminator = Some(MirInstruction::Jump {
target: merge_block,
});
mir_func.blocks.insert(final_else_block, else_block_obj);
// merge block
let merge_block_obj = crate::mir::BasicBlock::new(merge_block);
mir_func.blocks.insert(merge_block, merge_block_obj);
self.current_block_id = merge_block;
Ok(())
}
// === Utilities ===
fn finalize_block(
mir_func: &mut MirFunction,
block_id: BasicBlockId,
instructions: Vec<MirInstruction>,
terminator: MirInstruction,
) {
if let Some(block) = mir_func.blocks.get_mut(&block_id) {
let inst_count = instructions.len();
block.instructions = instructions;
block.instruction_spans = vec![Span::unknown(); inst_count];
block.terminator = Some(terminator);
}
}
fn finalize_remaining_instructions(&mut self, mir_func: &mut MirFunction) {
if !self.current_instructions.is_empty() {
debug_log!(
"[joinir_block] Final block {:?} has {} remaining instructions",
self.current_block_id,
self.current_instructions.len()
);
if let Some(block) = mir_func.blocks.get_mut(&self.current_block_id) {
let inst_count = self.current_instructions.len();
block.instructions = std::mem::take(&mut self.current_instructions);
block.instruction_spans = vec![Span::unknown(); inst_count];
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_block_converter_exists() {
let converter = JoinIrBlockConverter::new();
assert_eq!(converter.current_block_id, BasicBlockId(0));
assert_eq!(converter.next_block_id, 1);
}
}

View File

@ -0,0 +1,133 @@
//! Phase 190: JoinIR Function Converter
//!
//! 責務: JoinIR の関数を MIR 関数に変換
//! - パラメータ・ローカル変数の設定
//! - ブロック変換の統合
//! - 関数署名の管理
use crate::ast::Span;
use crate::mir::join_ir::{JoinFunction, JoinInst, JoinModule};
use crate::mir::{
BasicBlockId, EffectMask, FunctionSignature, MirFunction, MirInstruction, MirModule, MirType,
ValueId,
};
use super::joinir_block_converter::JoinIrBlockConverter;
use super::JoinIrVmBridgeError;
use super::{convert_mir_like_inst, join_func_name};
pub(crate) struct JoinIrFunctionConverter;
impl JoinIrFunctionConverter {
/// JoinIR モジュール全体を MIR モジュールに変換
///
/// Phase 32 L-2.2 Step-3: テストから呼び出し可能に `pub(crate)` 化
pub(crate) fn convert_joinir_to_mir(
join_module: &JoinModule,
) -> Result<MirModule, JoinIrVmBridgeError> {
let mut mir_module = MirModule::new("joinir_bridge".to_string());
// Convert all JoinIR functions to MIR
for (func_id, join_func) in &join_module.functions {
debug_log!(
"[joinir_vm_bridge] Converting JoinFunction {} ({})",
func_id.0,
join_func.name
);
let mir_func = Self::convert_function(join_func)?;
mir_module
.functions
.insert(join_func_name(*func_id), mir_func);
}
Ok(mir_module)
}
/// JoinFunction → MirFunction 変換
///
/// # Phase 40拡張予定: Loop Exit PHI for If-in-loop
///
/// ## Current Implementation (Phase 34)
///
/// - Header PHI: ループ開始時の変数(ループ不変変数含む)
/// - Exit PHI: ループ終了時の変数(単純パターンのみ)
///
/// ## Phase 40 Extension Required
///
/// ### Problem
///
/// 現在、if-in-loopで修正される変数のloop exit PHIが生成されない。
///
/// ```nyash,ignore
/// local out = new ArrayBox()
/// loop(i < n) {
/// if fn(arr[i]) { out.push(arr[i]) } // ← out修正
/// i = i + 1
/// }
/// // Missing: phi out_exit = (out_header, out_if_modified)
/// ```
///
/// ### Solution (Phase 40-1)
///
/// JoinIR Frontend AST loweringで検出したif-in-loop修正変数を
/// JoinModule metadataに格納し、MIR loweringで読み取る。
pub(crate) fn convert_function(
join_func: &JoinFunction,
) -> Result<MirFunction, JoinIrVmBridgeError> {
// TODO(Phase 40-1): Generate loop exit PHI for if-in-loop modified variables
// Integration point: After loop body lowering, before exit block finalization
let entry_block = BasicBlockId(0);
// Create FunctionSignature
let param_types = join_func
.params
.iter()
.map(|_| MirType::Unknown)
.collect::<Vec<_>>();
let signature = FunctionSignature {
name: join_func.name.clone(),
params: param_types,
return_type: MirType::Unknown,
effects: EffectMask::PURE,
};
let mut mir_func = MirFunction::new(signature, entry_block);
mir_func.params = join_func.params.clone();
// Convert function body using BlockConverter
let mut block_converter = JoinIrBlockConverter::new();
block_converter.convert_function_body(&mut mir_func, &join_func.body)?;
// Debug: print all blocks
debug_log!(
"[joinir_vm_bridge] Function '{}' has {} blocks:",
mir_func.signature.name,
mir_func.blocks.len()
);
for (block_id, block) in &mir_func.blocks {
debug_log!(
" Block {:?}: {} instructions, terminator={:?}",
block_id,
block.instructions.len(),
block.terminator
);
}
Ok(mir_func)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_function_converter_exists() {
// Basic module structure test
assert!(true);
}
}

View File

@ -1,4 +1,5 @@
use super::{convert_join_function_to_mir, join_func_name, JoinIrVmBridgeError}; // Phase 190: Use modularized converter
use super::{join_func_name, JoinIrFunctionConverter, JoinIrVmBridgeError};
use crate::mir::join_ir::frontend::JoinFuncMetaMap; use crate::mir::join_ir::frontend::JoinFuncMetaMap;
use crate::mir::join_ir::JoinModule; use crate::mir::join_ir::JoinModule;
use crate::mir::{MirFunction, MirModule}; use crate::mir::{MirFunction, MirModule};
@ -33,8 +34,8 @@ pub fn convert_join_module_to_mir_with_meta(
join_func.name join_func.name
); );
// 2. 基本のMIR変換既存ロジック // 2. 基本のMIR変換Phase 190: modularized converter
let mir_func = convert_join_function_to_mir(join_func)?; let mir_func = JoinIrFunctionConverter::convert_function(join_func)?;
// 3. Phase 40-1: if_modified_varsがあればloop exit PHI生成 // 3. Phase 40-1: if_modified_varsがあればloop exit PHI生成
if let Some(m) = meta.get(func_id) { if let Some(m) = meta.get(func_id) {

View File

@ -37,13 +37,19 @@ mod logging {
} }
mod convert; mod convert;
// Phase 190: Modular converters
mod joinir_function_converter;
mod joinir_block_converter;
mod meta; mod meta;
mod runner; mod runner;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub(crate) use convert::{convert_join_function_to_mir, convert_joinir_to_mir}; // Phase 190: Use modularized converters
pub(crate) use convert::convert_joinir_to_mir;
pub(crate) use convert::convert_mir_like_inst; // helper for sub-modules
pub(crate) use joinir_function_converter::JoinIrFunctionConverter;
pub use meta::convert_join_module_to_mir_with_meta; pub use meta::convert_join_module_to_mir_with_meta;
pub use runner::run_joinir_via_vm; pub use runner::run_joinir_via_vm;