From d9ff3f60ff37fb28de7cf1944afb6fe05a65077e Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sun, 21 Dec 2025 06:11:53 +0900 Subject: [PATCH] refactor(joinir): Phase 260 P0.1 Step 4 - Extract type_propagation.rs (70 lines) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract propagate_value_type_for_inst to dedicated type_propagation module. Handles type info flow from JoinIR→MIR merge (SSOT + fallback inference). Changes: - NEW: rewriter/type_propagation.rs - propagate_value_type_for_inst - CHANGED: instruction_rewriter.rs - import from type_propagation (deleted local fn) - CHANGED: rewriter/mod.rs - declare type_propagation module Design: - SSOT: Prefer type info from JoinIR source function metadata - Fallback: Infer from instruction structure (Const/Copy/BinOp/Compare) - LLVM: Ensures '+' stays numeric (not concat_hh_mixed) Reduction: - instruction_rewriter.rs: 1466 → 1396 lines (-70) Next: Start terminator.rs extraction (Branch/Jump/Return remapping) --- .../joinir/merge/instruction_rewriter.rs | 74 +---------- .../control_flow/joinir/merge/rewriter/mod.rs | 3 +- .../joinir/merge/rewriter/type_propagation.rs | 116 ++++++++++++++++++ 3 files changed, 120 insertions(+), 73 deletions(-) create mode 100644 src/mir/builder/control_flow/joinir/merge/rewriter/type_propagation.rs diff --git a/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs b/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs index 8d52ed44..4a1eb29e 100644 --- a/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs +++ b/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs @@ -25,78 +25,8 @@ use std::collections::BTreeSet; // Phase 260 P0.1 Step 3: Import from helpers module use super::rewriter::helpers::is_skippable_continuation; - -fn propagate_value_type_for_inst( - builder: &mut crate::mir::builder::MirBuilder, - source_func: &MirFunction, - old_inst: &MirInstruction, - new_inst: &MirInstruction, -) { - let Some(_) = builder.scope_ctx.current_function else { - return; - }; - - let (old_dst, new_dst) = match (old_inst, new_inst) { - (MirInstruction::Const { dst: o, .. }, MirInstruction::Const { dst: n, .. }) => { - (o, n) - } - (MirInstruction::BinOp { dst: o, .. }, MirInstruction::BinOp { dst: n, .. }) => (o, n), - (MirInstruction::UnaryOp { dst: o, .. }, MirInstruction::UnaryOp { dst: n, .. }) => (o, n), - (MirInstruction::Compare { dst: o, .. }, MirInstruction::Compare { dst: n, .. }) => (o, n), - (MirInstruction::Load { dst: o, .. }, MirInstruction::Load { dst: n, .. }) => (o, n), - (MirInstruction::Cast { dst: o, .. }, MirInstruction::Cast { dst: n, .. }) => (o, n), - (MirInstruction::TypeOp { dst: o, .. }, MirInstruction::TypeOp { dst: n, .. }) => (o, n), - (MirInstruction::ArrayGet { dst: o, .. }, MirInstruction::ArrayGet { dst: n, .. }) => (o, n), - (MirInstruction::Copy { dst: o, .. }, MirInstruction::Copy { dst: n, .. }) => (o, n), - (MirInstruction::NewBox { dst: o, .. }, MirInstruction::NewBox { dst: n, .. }) => (o, n), - (MirInstruction::TypeCheck { dst: o, .. }, MirInstruction::TypeCheck { dst: n, .. }) => (o, n), - (MirInstruction::Phi { dst: o, .. }, MirInstruction::Phi { dst: n, .. }) => (o, n), - _ => return, - }; - - // Prefer SSOT from the source MIR (JoinIR→MIR bridge may have hints). - if let Some(ty) = source_func.metadata.value_types.get(old_dst).cloned() { - builder.type_ctx.value_types.insert(*new_dst, ty); - return; - } - - // Fallback inference from the rewritten instruction itself. - // - // This is important for the LLVM harness: it relies on `dst_type` hints to keep `+` - // as numeric add instead of `concat_hh_mixed` when types are otherwise unknown. - match new_inst { - MirInstruction::Const { dst, value } if dst == new_dst => { - let ty = match value { - ConstValue::Integer(_) => Some(MirType::Integer), - ConstValue::Float(_) => Some(MirType::Float), - ConstValue::Bool(_) => Some(MirType::Bool), - ConstValue::String(_) => Some(MirType::String), - ConstValue::Void => Some(MirType::Void), - _ => None, - }; - if let Some(ty) = ty { - builder.type_ctx.value_types.insert(*dst, ty); - } - } - MirInstruction::Copy { dst, src } if dst == new_dst => { - if let Some(src_ty) = builder.type_ctx.value_types.get(src).cloned() { - builder.type_ctx.value_types.insert(*dst, src_ty); - } - } - MirInstruction::BinOp { dst, lhs, rhs, .. } if dst == new_dst => { - let lhs_ty = builder.type_ctx.value_types.get(lhs); - let rhs_ty = builder.type_ctx.value_types.get(rhs); - if matches!(lhs_ty, Some(MirType::Integer)) && matches!(rhs_ty, Some(MirType::Integer)) - { - builder.type_ctx.value_types.insert(*dst, MirType::Integer); - } - } - MirInstruction::Compare { dst, .. } if dst == new_dst => { - builder.type_ctx.value_types.insert(*dst, MirType::Bool); - } - _ => {} - } -} +// Phase 260 P0.1 Step 4: Import from type_propagation module +use super::rewriter::type_propagation::propagate_value_type_for_inst; /// Phase 4: Merge ALL functions and rewrite instructions /// diff --git a/src/mir/builder/control_flow/joinir/merge/rewriter/mod.rs b/src/mir/builder/control_flow/joinir/merge/rewriter/mod.rs index cb32c9d3..04100521 100644 --- a/src/mir/builder/control_flow/joinir/merge/rewriter/mod.rs +++ b/src/mir/builder/control_flow/joinir/merge/rewriter/mod.rs @@ -21,9 +21,9 @@ // Modules (extracted): // - logging: DEBUG-177 style verbose logs ✅ // - helpers: Small pure functions (is_skippable_continuation) ✅ +// - type_propagation: Type propagation (propagate_value_type_for_inst) ✅ // Future modules (pending): -// - type_propagation: propagate_value_type_for_inst // - terminator: Branch/Jump/Return remapping // - exit_line: ExitLine/exit-phi wiring // - carriers: loop_invariants, exit_bindings @@ -32,6 +32,7 @@ pub(super) mod helpers; // Phase 260 P0.1 Step 3: Helpers extracted ✅ pub(super) mod logging; // Phase 260 P0.1 Step 2: Logging extracted ✅ +pub(super) mod type_propagation; // Phase 260 P0.1 Step 4: Type propagation extracted ✅ // Re-export public API pub(super) use helpers::is_skippable_continuation; // Phase 260 P0.1 Step 3: From helpers ✅ diff --git a/src/mir/builder/control_flow/joinir/merge/rewriter/type_propagation.rs b/src/mir/builder/control_flow/joinir/merge/rewriter/type_propagation.rs new file mode 100644 index 00000000..85e2c25e --- /dev/null +++ b/src/mir/builder/control_flow/joinir/merge/rewriter/type_propagation.rs @@ -0,0 +1,116 @@ +//! Type propagation utilities for instruction rewriter +//! +//! Phase 260 P0.1 Step 4: Extracted from instruction_rewriter.rs (lines 29-99) +//! Propagates type information from JoinIR source to HOST MIR during merge. + +use crate::mir::types::ConstValue; +use crate::mir::{MirFunction, MirInstruction, MirType}; + +/// Propagate value type information from source instruction to remapped instruction +/// +/// This function ensures type information flows correctly from JoinIR→MIR merge: +/// 1. **SSOT from source**: Prefer type info from JoinIR source function metadata +/// 2. **Fallback inference**: Infer from instruction structure if no source hint +/// +/// ## Why This Matters +/// +/// The LLVM harness relies on `dst_type` hints to keep `+` as numeric add +/// instead of `concat_hh_mixed` when types are otherwise unknown. +/// +/// ## Supported Instructions +/// +/// - Const, BinOp, UnaryOp, Compare, Load, Cast, TypeOp +/// - ArrayGet, Copy, NewBox, TypeCheck, Phi +/// +/// ## Example +/// +/// ```ignore +/// // Before remapping +/// let old_inst = MirInstruction::Const { +/// dst: ValueId(42), // JoinIR value +/// value: ConstValue::Integer(10), +/// }; +/// +/// // After remapping +/// let new_inst = MirInstruction::Const { +/// dst: ValueId(123), // HOST value +/// value: ConstValue::Integer(10), +/// }; +/// +/// // Propagate type: ValueId(123) → MirType::Integer +/// propagate_value_type_for_inst(builder, source_func, &old_inst, &new_inst); +/// ``` +pub(in crate::mir::builder::control_flow::joinir::merge) fn propagate_value_type_for_inst( + builder: &mut crate::mir::builder::MirBuilder, + source_func: &MirFunction, + old_inst: &MirInstruction, + new_inst: &MirInstruction, +) { + let Some(_) = builder.scope_ctx.current_function else { + return; + }; + + let (old_dst, new_dst) = match (old_inst, new_inst) { + (MirInstruction::Const { dst: o, .. }, MirInstruction::Const { dst: n, .. }) => (o, n), + (MirInstruction::BinOp { dst: o, .. }, MirInstruction::BinOp { dst: n, .. }) => (o, n), + (MirInstruction::UnaryOp { dst: o, .. }, MirInstruction::UnaryOp { dst: n, .. }) => (o, n), + (MirInstruction::Compare { dst: o, .. }, MirInstruction::Compare { dst: n, .. }) => (o, n), + (MirInstruction::Load { dst: o, .. }, MirInstruction::Load { dst: n, .. }) => (o, n), + (MirInstruction::Cast { dst: o, .. }, MirInstruction::Cast { dst: n, .. }) => (o, n), + (MirInstruction::TypeOp { dst: o, .. }, MirInstruction::TypeOp { dst: n, .. }) => (o, n), + (MirInstruction::ArrayGet { dst: o, .. }, MirInstruction::ArrayGet { dst: n, .. }) => { + (o, n) + } + (MirInstruction::Copy { dst: o, .. }, MirInstruction::Copy { dst: n, .. }) => (o, n), + (MirInstruction::NewBox { dst: o, .. }, MirInstruction::NewBox { dst: n, .. }) => (o, n), + (MirInstruction::TypeCheck { dst: o, .. }, MirInstruction::TypeCheck { dst: n, .. }) => { + (o, n) + } + (MirInstruction::Phi { dst: o, .. }, MirInstruction::Phi { dst: n, .. }) => (o, n), + _ => return, + }; + + // Prefer SSOT from the source MIR (JoinIR→MIR bridge may have hints). + if let Some(ty) = source_func.metadata.value_types.get(old_dst).cloned() { + builder.type_ctx.value_types.insert(*new_dst, ty); + return; + } + + // Fallback inference from the rewritten instruction itself. + // + // This is important for the LLVM harness: it relies on `dst_type` hints to keep `+` + // as numeric add instead of `concat_hh_mixed` when types are otherwise unknown. + match new_inst { + MirInstruction::Const { dst, value } if dst == new_dst => { + let ty = match value { + ConstValue::Integer(_) => Some(MirType::Integer), + ConstValue::Float(_) => Some(MirType::Float), + ConstValue::Bool(_) => Some(MirType::Bool), + ConstValue::String(_) => Some(MirType::String), + ConstValue::Void => Some(MirType::Void), + _ => None, + }; + if let Some(ty) = ty { + builder.type_ctx.value_types.insert(*dst, ty); + } + } + MirInstruction::Copy { dst, src } if dst == new_dst => { + if let Some(src_ty) = builder.type_ctx.value_types.get(src).cloned() { + builder.type_ctx.value_types.insert(*dst, src_ty); + } + } + MirInstruction::BinOp { dst, lhs, rhs, .. } if dst == new_dst => { + let lhs_ty = builder.type_ctx.value_types.get(lhs); + let rhs_ty = builder.type_ctx.value_types.get(rhs); + if matches!(lhs_ty, Some(MirType::Integer)) + && matches!(rhs_ty, Some(MirType::Integer)) + { + builder.type_ctx.value_types.insert(*dst, MirType::Integer); + } + } + MirInstruction::Compare { dst, .. } if dst == new_dst => { + builder.type_ctx.value_types.insert(*dst, MirType::Bool); + } + _ => {} + } +}