Files
hakorune/src/mir/utils/phi_helpers.rs
nyash-codex 2db8ff72d0 refactor(mir): Remove CoreContext legacy fields (Phase 2-2/7)
完全移行→削除の安全順序(Option C)に従い、CoreContext の
deprecated フィールドと sync helpers を完全削除。

## Changes
- Migrated all access sites to core_ctx.* (SSOT allocators)
  - utils.rs: value_gen (3 sites), block_gen (1 site), temp_slot_counter (1 site)
  - loop_api.rs: block_gen (1 site)
  - phi_helpers.rs: value_gen (1 site)
  - builder.rs: sync helpers (2 methods), test assertions (2 sites)
- Removed 5 deprecated fields from builder.rs
  - value_gen: ValueIdGenerator
  - block_gen: BasicBlockIdGenerator
  - next_binding_id: u32
  - temp_slot_counter: u32
  - debug_join_counter: u32
- Removed sync helper calls (allocate_binding_id, debug_next_join_id)
- Removed field initializations from MirBuilder::new()
- Maintained Phase 136 P0 SSOT structure (next_value_id() remains as high-level API)

## Tests
- cargo build --release: PASS
- cargo test --release --lib: 1029 passed (4 pre-existing failures)
- Deprecation warnings: 435 → 456 (+21)
  Note: Warnings increased due to remaining deprecated field *uses* being exposed
  after removing the field *definitions*. This is expected during migration.

## Code metrics
- Net reduction: 40 lines (-56 removed, +16 modifications)
- Files changed: 4 (builder.rs, utils.rs, loop_api.rs, phi_helpers.rs)

Phase 2 Progress: 2/7 contexts complete (MetadataContext , CoreContext )
2025-12-15 23:05:36 +09:00

287 lines
9.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* PHI命令挿入ユーティリティ - Phase 4: PHI挿入パターン統一
*
* ## 目的
* builder内の重複するPHI挿入パターン26箇所を統一し、50-100行削減
*
* ## 設計原則
* 1. SSA不変条件の維持predecessor対応の厳密さ
* 2. 既存の`insert_phi_at_head`との統合
* 3. 段階的移行のための後方互換性
*
* ## 使用例
* ```rust
* // Before (5-7行)
* let phi_val = self.value_gen.next();
* let inputs = vec![(pred1, val1), (pred2, val2)];
* if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) {
* crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, phi_val, inputs);
* } else {
* self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?;
* }
*
* // After (1行, 80-85%削減)
* let phi_val = self.insert_phi(vec![(pred1, val1), (pred2, val2)])?;
* ```
*/
use crate::mir::builder::MirBuilder;
use crate::mir::{BasicBlockId, MirInstruction, ValueId};
/// PHI挿入ヘルパー - MirBuilderへのextension methods
impl MirBuilder {
/// **標準PHI挿入メソッド** - 現在のブロックに複数入力のPHI命令を挿入
///
/// ## 引数
/// - `inputs`: Vec<(predecessor_block, value_from_that_block)>
///
/// ## 戻り値
/// - 新しく割り当てられたPHI命令の結果ValueId
///
/// ## 使用場面
/// - If/Else合流2入力
/// - ループヘッダー(初期値+backedge
/// - 短絡評価のマージ
/// - match式の合流
///
/// ## 例
/// ```rust
/// // If/Else合流
/// let phi_val = self.insert_phi(vec![
/// (then_block, then_value),
/// (else_block, else_value),
/// ])?;
///
/// // ループヘッダー
/// let loop_var = self.insert_phi(vec![
/// (entry_block, init_value),
/// (backedge_block, updated_value),
/// ])?;
/// ```
#[inline]
pub fn insert_phi(&mut self, inputs: Vec<(BasicBlockId, ValueId)>) -> Result<ValueId, String> {
// Phase 25.1b fix: Use function-local ID allocator to avoid SSA verification failures
// This prevents PHI dst ValueIds from colliding with function-local IDs allocated later.
// Same pattern as pin_to_slot() and the loop builder fix in e2d061d1.
let phi_val = if let Some(ref mut f) = self.current_function {
f.next_value_id() // Function context: use local ID allocator
} else {
self.core_ctx.next_value() // Module context: use core_ctx SSOT
};
// 統一された挿入ロジック(既存パターンと完全互換)
if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) {
// CFG経由の正規化挿入predecessor順序の正規化を含む
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
func,
cur_bb,
phi_val,
inputs,
self.metadata_ctx.current_span(),
);
} else {
// フォールバック: 直接emit主にテストや特殊ケース用
self.emit_instruction(MirInstruction::Phi {
dst: phi_val,
inputs,
type_hint: None, // Phase 63-6: Legacy path, no type hint
})?;
}
Ok(phi_val)
}
/// **事前割り当てPHI挿入** - ValueIdを事前に確保済みの場合に使用
///
/// ## 引数
/// - `dst`: 事前に割り当てられたValueId結果の格納先
/// - `inputs`: Vec<(predecessor_block, value_from_that_block)>
///
/// ## 使用場面
/// - 複雑なif式で結果ValueIdを先に確保している場合
/// - PHI命令の結果を複数箇所で参照する必要がある場合
///
/// ## 重要: ValueId割り当てルール
/// `dst`は必ず関数コンテキストに適したアロケーターで確保すること:
/// ```rust
/// // ✅ 正しい: 関数ローカルアロケーター使用
/// let result_val = if let Some(ref mut f) = self.current_function {
/// f.next_value_id()
/// } else {
/// self.value_gen.next()
/// };
/// self.insert_phi_with_dst(result_val, vec![...])?;
///
/// // ❌ 間違い: 常にグローバルアロケーター使用SSA違反の原因
/// let result_val = self.value_gen.next();
/// ```
///
/// ## 例
/// ```rust
/// let result_val = if let Some(ref mut f) = self.current_function {
/// f.next_value_id() // 関数コンテキスト: ローカルID
/// } else {
/// self.value_gen.next() // モジュールコンテキスト: グローバルID
/// };
/// // ... 複雑なロジック ...
/// self.insert_phi_with_dst(result_val, vec![
/// (then_block, then_value),
/// (else_block, else_value),
/// ])?;
/// ```
#[inline]
pub fn insert_phi_with_dst(
&mut self,
dst: ValueId,
inputs: Vec<(BasicBlockId, ValueId)>,
) -> Result<(), String> {
// 統一された挿入ロジック(既存パターンと完全互換)
if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) {
// CFG経由の正規化挿入predecessor順序の正規化を含む
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
func,
cur_bb,
dst,
inputs,
self.metadata_ctx.current_span(),
);
} else {
// フォールバック: 直接emit主にテストや特殊ケース用
self.emit_instruction(MirInstruction::Phi {
dst,
inputs,
type_hint: None, // Phase 63-6: Legacy path, no type hint
})?;
}
Ok(())
}
/// **単一入力PHI挿入** - 変数のmaterialization具現化
///
/// ## 使用場面
/// - If/Elseブランチのエントリーでの変数具現化
/// - ループ内での変数の再定義
///
/// ## 例
/// ```rust
/// // 変数をブランチエントリーで具現化
/// for (name, &pre_v) in pre_if_var_map.iter() {
/// let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
/// self.variable_map.insert(name.clone(), phi_val);
/// }
/// ```
#[inline]
pub fn insert_phi_single(
&mut self,
pred: BasicBlockId,
value: ValueId,
) -> Result<ValueId, String> {
self.insert_phi(vec![(pred, value)])
}
/// **2入力PHI挿入** - If/Else合流の最頻出パターン用
///
/// ## 引数
/// - `pred1`, `val1`: 第1のpredecessor通常はthen-branch
/// - `pred2`, `val2`: 第2のpredecessor通常はelse-branch
///
/// ## 例
/// ```rust
/// // If/Else合流
/// let result = self.insert_phi_binary(
/// then_exit, then_value,
/// else_exit, else_value
/// )?;
/// ```
#[inline]
pub fn insert_phi_binary(
&mut self,
pred1: BasicBlockId,
val1: ValueId,
pred2: BasicBlockId,
val2: ValueId,
) -> Result<ValueId, String> {
self.insert_phi(vec![(pred1, val1), (pred2, val2)])
}
/// **ループヘッダーPHI挿入** - セマンティック明確化版
///
/// ## 引数
/// - `entry_pred`: ループに入る前のブロック
/// - `init_value`: 初期値
/// - `backedge_pred`: ループ本体の末尾ブロック
/// - `updated_value`: ループ内で更新された値
///
/// ## 例
/// ```rust
/// let loop_counter = self.insert_phi_loop_header(
/// entry_block, zero_value,
/// backedge_block, incremented_value
/// )?;
/// ```
#[inline]
pub fn insert_phi_loop_header(
&mut self,
entry_pred: BasicBlockId,
init_value: ValueId,
backedge_pred: BasicBlockId,
updated_value: ValueId,
) -> Result<ValueId, String> {
// ループヘッダーPHIは論理的に[entry, backedge]の順序が自然
self.insert_phi(vec![
(entry_pred, init_value),
(backedge_pred, updated_value),
])
}
/// **短絡評価用PHI挿入** - AND/ORの合流点用
///
/// ## 引数
/// - `short_circuit_pred`: 短絡したブロック(評価せずに結果確定)
/// - `short_circuit_value`: 短絡時の値AND: false, OR: true
/// - `evaluated_pred`: RHSを評価したブロック
/// - `evaluated_value`: RHS評価結果
///
/// ## 例
/// ```rust
/// // AND短絡: false || evaluated_rhs
/// let and_result = self.insert_phi_short_circuit(
/// lhs_false_block, false_value,
/// rhs_eval_block, rhs_value
/// )?;
///
/// // OR短絡: true || evaluated_rhs
/// let or_result = self.insert_phi_short_circuit(
/// lhs_true_block, true_value,
/// rhs_eval_block, rhs_value
/// )?;
/// ```
#[inline]
pub fn insert_phi_short_circuit(
&mut self,
short_circuit_pred: BasicBlockId,
short_circuit_value: ValueId,
evaluated_pred: BasicBlockId,
evaluated_value: ValueId,
) -> Result<ValueId, String> {
self.insert_phi(vec![
(short_circuit_pred, short_circuit_value),
(evaluated_pred, evaluated_value),
])
}
}
#[cfg(test)]
mod tests {
// ユニットテストは実際のMirBuilder構造が必要なため、
// 統合テストでの検証を推奨smoke testsで実証
#[test]
fn test_phi_helpers_exist() {
// コンパイル時にメソッドの存在を確認
// 実行時テストはsmoke testsで行う
}
}