diff --git a/src/backend/mir_interpreter/exec.rs b/src/backend/mir_interpreter/exec.rs index 8b130dc6..35cb6480 100644 --- a/src/backend/mir_interpreter/exec.rs +++ b/src/backend/mir_interpreter/exec.rs @@ -172,7 +172,7 @@ impl MirInterpreter { self.last_block = Some(block.id); self.last_inst_index = Some(idx); self.last_inst = Some(inst.clone()); - if let MirInstruction::Phi { dst, inputs } = inst { + if let MirInstruction::Phi { dst, inputs, .. } = inst { let dst_id = *dst; if trace_phi { let in_preds: Vec<_> = inputs.iter().map(|(bb, _)| *bb).collect(); diff --git a/src/mir/basic_block.rs b/src/mir/basic_block.rs index 10d1e339..d11931b9 100644 --- a/src/mir/basic_block.rs +++ b/src/mir/basic_block.rs @@ -324,7 +324,7 @@ impl BasicBlock { incoming: (BasicBlockId, ValueId), ) -> Result<(), String> { for inst in &mut self.instructions { - if let MirInstruction::Phi { dst, inputs } = inst { + if let MirInstruction::Phi { dst, inputs, .. } = inst { if *dst == phi_dst { inputs.push(incoming); return Ok(()); @@ -580,6 +580,7 @@ mod tests { let phi_inst = MirInstruction::Phi { dst: ValueId::new(0), inputs: vec![(BasicBlockId::new(1), ValueId::new(1))], + type_hint: None, // Phase 63-6: Test code, no type hint }; bb.add_instruction(phi_inst); diff --git a/src/mir/builder.rs b/src/mir/builder.rs index 0286faca..ae9953d9 100644 --- a/src/mir/builder.rs +++ b/src/mir/builder.rs @@ -604,7 +604,7 @@ impl MirBuilder { .map(|f| f.signature.name.clone()); let _dbg_region_id = self.debug_current_region_id(); // P0: PHI の軽量補強と観測は、関数ブロック取得前に実施して借用競合を避ける - if let MirInstruction::Phi { dst, inputs } = &instruction { + if let MirInstruction::Phi { dst, inputs, .. } = &instruction { origin::phi::propagate_phi_meta(self, *dst, inputs); observe::ssa::emit_phi(self, *dst, inputs); } @@ -815,7 +815,7 @@ impl MirBuilder { if let Some(block_data) = function.get_block_mut(block) { // Find PHI instruction with matching dst for inst in &mut block_data.instructions { - if let MirInstruction::Phi { dst, inputs } = inst { + if let MirInstruction::Phi { dst, inputs, .. } = inst { if *dst == phi_id { *inputs = new_inputs; return Ok(()); diff --git a/src/mir/builder/control_flow.rs b/src/mir/builder/control_flow.rs index 5b55b058..75873efb 100644 --- a/src/mir/builder/control_flow.rs +++ b/src/mir/builder/control_flow.rs @@ -542,7 +542,7 @@ impl super::MirBuilder { values.insert(*v); } } - MirInstruction::Phi { dst, inputs } => { + MirInstruction::Phi { dst, inputs, type_hint: None } => { values.insert(*dst); for (_, val) in inputs { values.insert(*val); @@ -651,12 +651,13 @@ impl super::MirBuilder { MirInstruction::Return { value } => MirInstruction::Return { value: value.map(remap_value), }, - MirInstruction::Phi { dst, inputs } => MirInstruction::Phi { + 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), diff --git a/src/mir/builder/exprs_peek.rs b/src/mir/builder/exprs_peek.rs index 5ee694c8..bc3b4dad 100644 --- a/src/mir/builder/exprs_peek.rs +++ b/src/mir/builder/exprs_peek.rs @@ -130,6 +130,7 @@ impl super::MirBuilder { self.emit_instruction(super::MirInstruction::Phi { dst: result_val, inputs: phi_inputs, + type_hint: None, // Phase 63-6: Legacy path, no type hint })?; } Ok(result_val) diff --git a/src/mir/builder/if_form.rs b/src/mir/builder/if_form.rs index 69742d07..e49f0c57 100644 --- a/src/mir/builder/if_form.rs +++ b/src/mir/builder/if_form.rs @@ -32,7 +32,7 @@ impl<'a> PhiBuilderOps for ToplevelOps<'a> { self.0.current_span, ); } else { - self.0.emit_instruction(MirInstruction::Phi { dst, inputs })?; + self.0.emit_instruction(MirInstruction::Phi { dst, inputs, type_hint: None })?; } Ok(()) } diff --git a/src/mir/builder/phi.rs b/src/mir/builder/phi.rs index 7002bbb5..30a98cef 100644 --- a/src/mir/builder/phi.rs +++ b/src/mir/builder/phi.rs @@ -91,6 +91,7 @@ impl MirBuilder { self.emit_instruction(MirInstruction::Phi { dst: merged, inputs, + type_hint: None, // Phase 63-6: Legacy path, no type hint })?; } self.variable_map.insert(pin_name.clone(), merged); diff --git a/src/mir/instruction.rs b/src/mir/instruction.rs index 1b81b0fd..ba9f30c2 100644 --- a/src/mir/instruction.rs +++ b/src/mir/instruction.rs @@ -129,9 +129,17 @@ pub enum MirInstruction { // === SSA Phi Function === /// SSA phi function for merging values from different paths /// `%dst = phi [%val1 from %bb1, %val2 from %bb2, ...]` + /// + /// # Phase 63-6: Type Hint Support + /// + /// `type_hint` field stores type information from JoinIR (Select/IfMerge) + /// to enable type inference without scanning PHI inputs. + /// - `Some(MirType)`: Type is known from JoinIR (P1 cases: IfSelectTest.simple/local) + /// - `None`: Type must be inferred from PHI inputs (legacy behavior) Phi { dst: ValueId, inputs: Vec<(super::BasicBlockId, ValueId)>, + type_hint: Option, // Phase 63-6: JoinIR type hint }, // === Box Operations === diff --git a/src/mir/instruction_kinds/mod.rs b/src/mir/instruction_kinds/mod.rs index 54cc6a88..73204708 100644 --- a/src/mir/instruction_kinds/mod.rs +++ b/src/mir/instruction_kinds/mod.rs @@ -541,7 +541,7 @@ inst_meta! { inst_meta! { pub struct PhiInst { dst: ValueId, inputs: Vec<(BasicBlockId, ValueId)> } => { - from_mir = |i| match i { MirInstruction::Phi { dst, inputs } => Some(PhiInst { dst: *dst, inputs: inputs.clone() }), _ => None }; + from_mir = |i| match i { MirInstruction::Phi { dst, inputs, .. } => Some(PhiInst { dst: *dst, inputs: inputs.clone() }), _ => None }; effects = |_: &Self| EffectMask::PURE; dst = |s: &Self| Some(s.dst); used = |s: &Self| s.inputs.iter().map(|(_, v)| *v).collect(); diff --git a/src/mir/join_ir/lowering/loop_form_intake.rs b/src/mir/join_ir/lowering/loop_form_intake.rs index d0cefc77..11e4ba93 100644 --- a/src/mir/join_ir/lowering/loop_form_intake.rs +++ b/src/mir/join_ir/lowering/loop_form_intake.rs @@ -94,7 +94,7 @@ pub(crate) fn intake_loop_form( let mut carrier_hint: Vec = Vec::new(); for inst in query.insts_in_block(loop_form.header) { - if let MirInstruction::Phi { dst, inputs } = inst { + if let MirInstruction::Phi { dst, inputs, .. } = inst { let name = inputs .iter() .find_map(|(_, v)| value_to_name.get(v).cloned()) diff --git a/src/mir/join_ir_vm_bridge/convert.rs b/src/mir/join_ir_vm_bridge/convert.rs index 108f1a70..dc75834e 100644 --- a/src/mir/join_ir_vm_bridge/convert.rs +++ b/src/mir/join_ir_vm_bridge/convert.rs @@ -491,17 +491,18 @@ Call {{\n\ cond, then_val, else_val, - type_hint: _, // Phase 63-3: MIR変換では現時点で未使用 + type_hint, // Phase 63-6: Type hint propagated to MIR Phi } => { // Phase 33-2: Select を MIR の if/phi に変換 - // 最小実装: cond/then/else/merge の 4 ブロック構造 + // Phase 63-6: PHI instruction with type hint from JoinIR debug_log!( - "[joinir_vm_bridge] Converting Select: dst={:?}, cond={:?}, then={:?}, else={:?}", + "[joinir_vm_bridge] Converting Select: dst={:?}, cond={:?}, then={:?}, else={:?}, type_hint={:?}", dst, cond, then_val, - else_val + else_val, + type_hint ); // 1. cond ブロック(現在のブロック) @@ -532,32 +533,29 @@ Call {{\n\ branch_terminator, ); - // 6. then ブロック: dst = then_val; jump merge + // 6. then ブロック: jump merge (no Copy, PHI will handle it) let mut then_block_obj = crate::mir::BasicBlock::new(then_block); - then_block_obj.instructions.push(MirInstruction::Copy { - dst: *dst, - src: *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 ブロック: dst = else_val; jump merge + // 7. else ブロック: jump merge (no Copy, PHI will handle it) let mut else_block_obj = crate::mir::BasicBlock::new(else_block); - else_block_obj.instructions.push(MirInstruction::Copy { - dst: *dst, - src: *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); + // 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 ブロックに移動 diff --git a/src/mir/loop_builder/loop_form.rs b/src/mir/loop_builder/loop_form.rs index acaf6e44..8b42354c 100644 --- a/src/mir/loop_builder/loop_form.rs +++ b/src/mir/loop_builder/loop_form.rs @@ -395,6 +395,7 @@ impl<'a> LoopBuilder<'a> { merge_block.add_instruction(MirInstruction::Phi { dst: phi_id, inputs: final_inputs, + type_hint: None, // Phase 63-6 }); } } diff --git a/src/mir/loop_builder/phi_ops.rs b/src/mir/loop_builder/phi_ops.rs index 6aaf647a..d9af8709 100644 --- a/src/mir/loop_builder/phi_ops.rs +++ b/src/mir/loop_builder/phi_ops.rs @@ -36,6 +36,7 @@ impl<'a> LoopBuilder<'a> { MirInstruction::Phi { dst: d, inputs: ins, + .. // Phase 63-6: Ignore type_hint in pattern matching } if *d == dst => { *ins = inputs.clone(); if block.instruction_spans.len() <= idx { @@ -58,6 +59,7 @@ impl<'a> LoopBuilder<'a> { let phi_inst = MirInstruction::Phi { dst, inputs: inputs.clone(), + type_hint: None, // Phase 63-6: Legacy path, no type hint }; block.instructions.insert(0, phi_inst); block.instruction_spans.insert(0, span); diff --git a/src/mir/phi_core/if_phi.rs b/src/mir/phi_core/if_phi.rs index 3be62398..9a3cd97a 100644 --- a/src/mir/phi_core/if_phi.rs +++ b/src/mir/phi_core/if_phi.rs @@ -136,7 +136,8 @@ pub fn infer_type_from_phi( ) -> Option { for (_bid, bb) in function.blocks.iter() { for inst in bb.instructions.iter() { - if let MirInstruction::Phi { dst, inputs } = inst { + if let MirInstruction::Phi { dst, inputs, .. } = inst { + // Phase 63-6: type_hint is ignored here, will be used in lifecycle.rs if *dst == ret_val { let mut it = inputs.iter().filter_map(|(_, v)| types.get(v)); if let Some(first) = it.next() { diff --git a/src/mir/printer_helpers.rs b/src/mir/printer_helpers.rs index 183e249b..89831eda 100644 --- a/src/mir/printer_helpers.rs +++ b/src/mir/printer_helpers.rs @@ -248,7 +248,7 @@ pub fn format_instruction( } } - MirInstruction::Phi { dst, inputs } => { + MirInstruction::Phi { dst, inputs, .. } => { let inputs_str = inputs .iter() .map(|(bb, val)| format!("[{}, {}]", val, bb)) diff --git a/src/mir/ssot/cf_common.rs b/src/mir/ssot/cf_common.rs index ca5d4316..e1205770 100644 --- a/src/mir/ssot/cf_common.rs +++ b/src/mir/ssot/cf_common.rs @@ -72,7 +72,7 @@ pub fn insert_phi_at_head_spanned( inputs.sort_by_key(|(bb, _)| bb.0); if let Some(bb) = f.get_block_mut(bb_id) { bb.insert_spanned_after_phis(SpannedInstruction { - inst: MirInstruction::Phi { dst, inputs }, + inst: MirInstruction::Phi { dst, inputs, type_hint: None }, span, }); } diff --git a/src/mir/utils/phi_helpers.rs b/src/mir/utils/phi_helpers.rs index 487d1092..d8a18c37 100644 --- a/src/mir/utils/phi_helpers.rs +++ b/src/mir/utils/phi_helpers.rs @@ -84,6 +84,7 @@ impl MirBuilder { self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs, + type_hint: None, // Phase 63-6: Legacy path, no type hint })?; } @@ -146,7 +147,11 @@ impl MirBuilder { ); } else { // フォールバック: 直接emit(主にテストや特殊ケース用) - self.emit_instruction(MirInstruction::Phi { dst, inputs })?; + self.emit_instruction(MirInstruction::Phi { + dst, + inputs, + type_hint: None, // Phase 63-6: Legacy path, no type hint + })?; } Ok(()) diff --git a/src/runner/json_v0_bridge/lowering/loop_.rs b/src/runner/json_v0_bridge/lowering/loop_.rs index b40d590a..63b86178 100644 --- a/src/runner/json_v0_bridge/lowering/loop_.rs +++ b/src/runner/json_v0_bridge/lowering/loop_.rs @@ -163,6 +163,7 @@ impl LoopFormOps for LoopFormJsonOps<'_> { if let MirInstruction::Phi { dst, inputs: phi_inputs, + .. // Phase 63-6: Ignore type_hint } = inst { if *dst == phi_id { diff --git a/src/runner/json_v1_bridge.rs b/src/runner/json_v1_bridge.rs index 4b53dedd..25be3685 100644 --- a/src/runner/json_v1_bridge.rs +++ b/src/runner/json_v1_bridge.rs @@ -273,6 +273,7 @@ pub fn try_parse_v1_to_module(json: &str) -> Result, String> { block_ref.add_instruction(MirInstruction::Phi { dst: ValueId::new(dst), inputs: pairs, + type_hint: None, // Phase 63-6 }); max_value_id = max_value_id.max(dst + 1); } diff --git a/src/runner/mir_json_emit.rs b/src/runner/mir_json_emit.rs index d2512636..9c070eb8 100644 --- a/src/runner/mir_json_emit.rs +++ b/src/runner/mir_json_emit.rs @@ -227,7 +227,7 @@ pub fn emit_mir_json_for_harness( } continue; } - if let I::Phi { dst, inputs } = inst { + if let I::Phi { dst, inputs, .. } = inst { let incoming: Vec<_> = inputs .iter() .map(|(b, v)| json!([v.as_u32(), b.as_u32()])) @@ -642,7 +642,7 @@ pub fn emit_mir_json_for_harness_bin( let mut emitted_defs: std::collections::HashSet = std::collections::HashSet::new(); for inst in &bb.instructions { - if let I::Phi { dst, inputs } = inst { + if let I::Phi { dst, inputs, .. } = inst { let incoming: Vec<_> = inputs .iter() .map(|(b, v)| json!([v.as_u32(), b.as_u32()])) diff --git a/src/runner/mir_json_v0.rs b/src/runner/mir_json_v0.rs index 44869828..827ae75c 100644 --- a/src/runner/mir_json_v0.rs +++ b/src/runner/mir_json_v0.rs @@ -179,6 +179,7 @@ pub fn parse_mir_v0_to_module(json: &str) -> Result { block_ref.add_instruction(MirInstruction::Phi { dst: ValueId::new(dst), inputs: pairs, + type_hint: None, // Phase 63-6 }); max_value_id = max_value_id.max(dst + 1); }