2025-11-27 02:58:38 +09:00
|
|
|
|
//! Phase 33: If/Else の Select 命令への lowering
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! 最小の if/else(副作用なし、単純な値選択)を JoinInst::Select に変換する。
|
2025-11-27 10:58:56 +09:00
|
|
|
|
//!
|
|
|
|
|
|
//! ## 責務分離(Phase 33-9.1)
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! **IfSelectLowerer の責務**:
|
|
|
|
|
|
//! - 単純 if/else(副作用なし、単一変数)を Select 命令に変換する
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! **非責務**:
|
|
|
|
|
|
//! - Loop の PHI には触らない(Loop lowering の責務)
|
2025-11-27 02:58:38 +09:00
|
|
|
|
|
|
|
|
|
|
use crate::mir::join_ir::JoinInst;
|
2025-11-27 03:28:32 +09:00
|
|
|
|
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
feat(joinir): Phase 63-4 infer_type_from_phi degradation design
Phase 63-4: infer_type_from_phi を『JoinIR 型ヒント優先+従来ロジックフォールバック』に縮退する仕様を設計(実装は Phase 63-5+)
## Changes
### Documentation Updates
- **README.md**: Added complete Phase 63-4 design (63-4.1 through 63-4.5)
- 63-4.1: Current state analysis (definition location, callsites, role, JoinIR preparation)
- 63-4.2: Degradation spec (type_hint priority + fallback pattern)
- 63-4.3: Representative cases and A/B testing strategy (P1/P2/P3)
- 63-4.4: Deletion conditions (5 conditions, current: 2/5 = 40%)
- 63-4.5: Phase 63-5 handoff (infer_type_from_phi_with_hint() implementation tasks)
- **PHI_BOX_INVENTORY.md**: Updated if_phi.rs entry with Phase 63-4 deletion plan
- Added: "Phase 63-4完了: infer_type_from_phi の JoinIR type_hint 優先への縮退案を設計(実装は Phase 63-5+)"
- **CURRENT_TASK.md**: Added Phase 63-4 section with summary of design work
## Design Highlights
### Degradation Pattern
```rust
pub fn infer_type_from_phi_with_hint(
function: &MirFunction,
ret_val: ValueId,
types: &BTreeMap<ValueId, MirType>,
type_hint: Option<MirType>,
) -> Option<MirType> {
if let Some(hint) = type_hint {
return Some(hint); // Route B: JoinIR priority (SSOT)
}
infer_type_from_phi(function, ret_val, types) // Route A: Fallback
}
```
### Representative Cases
- **P1**: IfSelectTest.simple/local (Phase 63-5 target)
- **P2**: read_quoted_from (Phase 63-6+ target)
- **P3**: MethodCall/Box constructors (Phase 64+ expansion)
### Deletion Conditions (2/5 achieved)
1. ✅ JoinIR has type_hint field (Phase 63-3)
2. ✅ Type hints populated for representative cases (Phase 63-2)
3. ⏳ Degraded to type_hint priority (Phase 63-5)
4. ⏳ P1 cases determined by type_hint only (Phase 63-5)
5. ⏳ All functions use type hints (Phase 64+)
## Files Changed
- docs/private/roadmap2/phases/phase-63-joinir-type-info/README.md
- docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md
- CURRENT_TASK.md
## Next Steps
Phase 63-5: Implement degradation for P1 cases (IfSelectTest.simple/local)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 17:58:06 +09:00
|
|
|
|
// Phase 63-2: Type hint inference from MIR
|
2025-11-27 02:58:38 +09:00
|
|
|
|
|
2025-11-29 11:53:57 +09:00
|
|
|
|
// Phase 61-1: If-in-loop context support
|
|
|
|
|
|
use super::if_phi_context::IfPhiContext;
|
|
|
|
|
|
|
2025-11-27 02:58:38 +09:00
|
|
|
|
pub struct IfSelectLowerer {
|
2025-11-27 09:30:54 +09:00
|
|
|
|
debug_level: u8,
|
2025-11-29 11:53:57 +09:00
|
|
|
|
// Phase 61-1: If-in-loop context (None = Pure If)
|
|
|
|
|
|
context: Option<IfPhiContext>,
|
2025-11-27 02:58:38 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
/// If/Else パターンの分類
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
|
enum IfPatternType {
|
|
|
|
|
|
/// Simple pattern: if cond { return 1 } else { return 2 }
|
|
|
|
|
|
Simple,
|
|
|
|
|
|
/// Local pattern: if cond { x = a } else { x = b }; return x
|
|
|
|
|
|
Local,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 検出された If/Else パターン情報
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
struct IfPattern {
|
|
|
|
|
|
pattern_type: IfPatternType,
|
|
|
|
|
|
cond: ValueId,
|
|
|
|
|
|
then_val: ValueId,
|
|
|
|
|
|
else_val: ValueId,
|
|
|
|
|
|
dst: Option<ValueId>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Branch 命令の情報
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
struct IfBranch {
|
|
|
|
|
|
cond: ValueId,
|
|
|
|
|
|
then_block: BasicBlockId,
|
|
|
|
|
|
else_block: BasicBlockId,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 02:58:38 +09:00
|
|
|
|
impl IfSelectLowerer {
|
2025-11-27 09:30:54 +09:00
|
|
|
|
pub fn new(debug_level: u8) -> Self {
|
2025-11-29 11:53:57 +09:00
|
|
|
|
Self {
|
|
|
|
|
|
debug_level,
|
|
|
|
|
|
context: None, // Phase 61-1: デフォルトは Pure If
|
|
|
|
|
|
}
|
2025-11-27 09:30:54 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Phase 33-8: debug-level backward compat wrapper
|
|
|
|
|
|
pub fn with_debug(debug: bool) -> Self {
|
2025-11-28 17:42:19 +09:00
|
|
|
|
Self {
|
|
|
|
|
|
debug_level: if debug { 1 } else { 0 },
|
2025-11-29 11:53:57 +09:00
|
|
|
|
context: None, // Phase 61-1: デフォルトは Pure If
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Phase 61-1: If-in-loop 用コンストラクタ
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Arguments
|
|
|
|
|
|
///
|
|
|
|
|
|
/// * `debug_level` - デバッグログレベル (0-3)
|
|
|
|
|
|
/// * `context` - If-in-loop コンテキスト(carrier_names 情報を含む)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Example
|
|
|
|
|
|
///
|
|
|
|
|
|
/// ```ignore
|
|
|
|
|
|
/// let context = IfPhiContext::for_loop_body(carrier_names);
|
|
|
|
|
|
/// let lowerer = IfSelectLowerer::with_context(debug_level, context);
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
pub fn with_context(debug_level: u8, context: IfPhiContext) -> Self {
|
|
|
|
|
|
Self {
|
|
|
|
|
|
debug_level,
|
|
|
|
|
|
context: Some(context),
|
2025-11-28 17:42:19 +09:00
|
|
|
|
}
|
2025-11-27 02:58:38 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// if/else が Select に lowering できるかチェック
|
2025-11-27 03:28:32 +09:00
|
|
|
|
pub fn can_lower_to_select(&self, func: &MirFunction, if_block_id: BasicBlockId) -> bool {
|
|
|
|
|
|
self.find_if_pattern(func, if_block_id).is_some()
|
2025-11-27 02:58:38 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// if/else を Select に変換
|
|
|
|
|
|
pub fn lower_if_to_select(
|
|
|
|
|
|
&self,
|
2025-11-27 03:28:32 +09:00
|
|
|
|
func: &MirFunction,
|
|
|
|
|
|
if_block_id: BasicBlockId,
|
2025-11-27 02:58:38 +09:00
|
|
|
|
) -> Option<JoinInst> {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
let pattern = self.find_if_pattern(func, if_block_id)?;
|
|
|
|
|
|
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// Phase 33-8: Level 1 - Basic lowering info
|
|
|
|
|
|
if self.debug_level >= 1 {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
eprintln!(
|
2025-11-27 09:30:54 +09:00
|
|
|
|
"[IfSelectLowerer] ✅ lowering {:?} pattern to Select",
|
2025-11-27 03:28:32 +09:00
|
|
|
|
pattern.pattern_type
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// Phase 33-8: Level 3 - Full pattern details
|
|
|
|
|
|
if self.debug_level >= 3 {
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] cond: {:?}", pattern.cond);
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] then_val: {:?}", pattern.then_val);
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] else_val: {:?}", pattern.else_val);
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] dst: {:?}", pattern.dst);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
// Select 命令を生成
|
|
|
|
|
|
let dst = pattern.dst.unwrap_or(pattern.then_val);
|
|
|
|
|
|
|
feat(joinir): Phase 63-4 infer_type_from_phi degradation design
Phase 63-4: infer_type_from_phi を『JoinIR 型ヒント優先+従来ロジックフォールバック』に縮退する仕様を設計(実装は Phase 63-5+)
## Changes
### Documentation Updates
- **README.md**: Added complete Phase 63-4 design (63-4.1 through 63-4.5)
- 63-4.1: Current state analysis (definition location, callsites, role, JoinIR preparation)
- 63-4.2: Degradation spec (type_hint priority + fallback pattern)
- 63-4.3: Representative cases and A/B testing strategy (P1/P2/P3)
- 63-4.4: Deletion conditions (5 conditions, current: 2/5 = 40%)
- 63-4.5: Phase 63-5 handoff (infer_type_from_phi_with_hint() implementation tasks)
- **PHI_BOX_INVENTORY.md**: Updated if_phi.rs entry with Phase 63-4 deletion plan
- Added: "Phase 63-4完了: infer_type_from_phi の JoinIR type_hint 優先への縮退案を設計(実装は Phase 63-5+)"
- **CURRENT_TASK.md**: Added Phase 63-4 section with summary of design work
## Design Highlights
### Degradation Pattern
```rust
pub fn infer_type_from_phi_with_hint(
function: &MirFunction,
ret_val: ValueId,
types: &BTreeMap<ValueId, MirType>,
type_hint: Option<MirType>,
) -> Option<MirType> {
if let Some(hint) = type_hint {
return Some(hint); // Route B: JoinIR priority (SSOT)
}
infer_type_from_phi(function, ret_val, types) // Route A: Fallback
}
```
### Representative Cases
- **P1**: IfSelectTest.simple/local (Phase 63-5 target)
- **P2**: read_quoted_from (Phase 63-6+ target)
- **P3**: MethodCall/Box constructors (Phase 64+ expansion)
### Deletion Conditions (2/5 achieved)
1. ✅ JoinIR has type_hint field (Phase 63-3)
2. ✅ Type hints populated for representative cases (Phase 63-2)
3. ⏳ Degraded to type_hint priority (Phase 63-5)
4. ⏳ P1 cases determined by type_hint only (Phase 63-5)
5. ⏳ All functions use type hints (Phase 64+)
## Files Changed
- docs/private/roadmap2/phases/phase-63-joinir-type-info/README.md
- docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md
- CURRENT_TASK.md
## Next Steps
Phase 63-5: Implement degradation for P1 cases (IfSelectTest.simple/local)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 17:58:06 +09:00
|
|
|
|
// Phase 63-2: MIR の Const 命令から型ヒントを推論
|
|
|
|
|
|
let type_hint = infer_type_from_mir_pattern(func, pattern.then_val)
|
|
|
|
|
|
.or_else(|| infer_type_from_mir_pattern(func, pattern.else_val));
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
Some(JoinInst::Select {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
cond: pattern.cond,
|
|
|
|
|
|
then_val: pattern.then_val,
|
|
|
|
|
|
else_val: pattern.else_val,
|
feat(joinir): Phase 63-4 infer_type_from_phi degradation design
Phase 63-4: infer_type_from_phi を『JoinIR 型ヒント優先+従来ロジックフォールバック』に縮退する仕様を設計(実装は Phase 63-5+)
## Changes
### Documentation Updates
- **README.md**: Added complete Phase 63-4 design (63-4.1 through 63-4.5)
- 63-4.1: Current state analysis (definition location, callsites, role, JoinIR preparation)
- 63-4.2: Degradation spec (type_hint priority + fallback pattern)
- 63-4.3: Representative cases and A/B testing strategy (P1/P2/P3)
- 63-4.4: Deletion conditions (5 conditions, current: 2/5 = 40%)
- 63-4.5: Phase 63-5 handoff (infer_type_from_phi_with_hint() implementation tasks)
- **PHI_BOX_INVENTORY.md**: Updated if_phi.rs entry with Phase 63-4 deletion plan
- Added: "Phase 63-4完了: infer_type_from_phi の JoinIR type_hint 優先への縮退案を設計(実装は Phase 63-5+)"
- **CURRENT_TASK.md**: Added Phase 63-4 section with summary of design work
## Design Highlights
### Degradation Pattern
```rust
pub fn infer_type_from_phi_with_hint(
function: &MirFunction,
ret_val: ValueId,
types: &BTreeMap<ValueId, MirType>,
type_hint: Option<MirType>,
) -> Option<MirType> {
if let Some(hint) = type_hint {
return Some(hint); // Route B: JoinIR priority (SSOT)
}
infer_type_from_phi(function, ret_val, types) // Route A: Fallback
}
```
### Representative Cases
- **P1**: IfSelectTest.simple/local (Phase 63-5 target)
- **P2**: read_quoted_from (Phase 63-6+ target)
- **P3**: MethodCall/Box constructors (Phase 64+ expansion)
### Deletion Conditions (2/5 achieved)
1. ✅ JoinIR has type_hint field (Phase 63-3)
2. ✅ Type hints populated for representative cases (Phase 63-2)
3. ⏳ Degraded to type_hint priority (Phase 63-5)
4. ⏳ P1 cases determined by type_hint only (Phase 63-5)
5. ⏳ All functions use type hints (Phase 64+)
## Files Changed
- docs/private/roadmap2/phases/phase-63-joinir-type-info/README.md
- docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md
- CURRENT_TASK.md
## Next Steps
Phase 63-5: Implement degradation for P1 cases (IfSelectTest.simple/local)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 17:58:06 +09:00
|
|
|
|
type_hint, // Phase 63-2: Const 命令から推論した型(Integer/Bool/String など)
|
2025-11-27 03:28:32 +09:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// MIR 関数から if/else パターンを探す
|
2025-11-28 17:42:19 +09:00
|
|
|
|
fn find_if_pattern(&self, func: &MirFunction, block_id: BasicBlockId) -> Option<IfPattern> {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
// 1. Block が Branch 命令で終わっているか確認
|
|
|
|
|
|
let block = func.blocks.get(&block_id)?;
|
|
|
|
|
|
let branch = match block.terminator.as_ref()? {
|
|
|
|
|
|
MirInstruction::Branch {
|
|
|
|
|
|
condition,
|
|
|
|
|
|
then_bb,
|
|
|
|
|
|
else_bb,
|
|
|
|
|
|
} => IfBranch {
|
|
|
|
|
|
cond: *condition,
|
|
|
|
|
|
then_block: *then_bb,
|
|
|
|
|
|
else_block: *else_bb,
|
|
|
|
|
|
},
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 2. then/else ブロックの構造を確認
|
|
|
|
|
|
let then_block = func.blocks.get(&branch.then_block)?;
|
|
|
|
|
|
let else_block = func.blocks.get(&branch.else_block)?;
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// Phase 33-10: PHI早期チェック(パターンマッチング前)
|
|
|
|
|
|
// JoinIRは「PHI生成器」であり「PHI変換器」ではない
|
|
|
|
|
|
// then/elseがJumpで終わる場合、merge blockにPHI命令があるか早期確認
|
2025-11-28 17:42:19 +09:00
|
|
|
|
if let Some(merge_block_id) =
|
|
|
|
|
|
self.get_merge_block_if_jump_pattern(&branch, then_block, else_block)
|
|
|
|
|
|
{
|
2025-11-27 17:05:46 +09:00
|
|
|
|
let merge_block = func.blocks.get(&merge_block_id)?;
|
2025-11-28 17:42:19 +09:00
|
|
|
|
if merge_block
|
|
|
|
|
|
.instructions
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.any(|inst| matches!(inst, MirInstruction::Phi { .. }))
|
|
|
|
|
|
{
|
2025-11-27 17:05:46 +09:00
|
|
|
|
if self.debug_level >= 2 {
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] ⏭️ PHI already exists in merge block, skipping");
|
|
|
|
|
|
}
|
|
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
// 3. simple パターンのチェック
|
|
|
|
|
|
if let Some(pattern) = self.try_match_simple_pattern(&branch, then_block, else_block) {
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// Phase 33-8: Level 2 - Pattern matching details
|
|
|
|
|
|
if self.debug_level >= 2 {
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] ✅ matched simple pattern");
|
2025-11-27 03:28:32 +09:00
|
|
|
|
}
|
|
|
|
|
|
return Some(pattern);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. local パターンのチェック
|
2025-11-28 17:42:19 +09:00
|
|
|
|
if let Some(pattern) = self.try_match_local_pattern(func, &branch, then_block, else_block) {
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// Phase 33-8: Level 2 - Pattern matching details
|
|
|
|
|
|
if self.debug_level >= 2 {
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] ✅ matched local pattern");
|
2025-11-27 03:28:32 +09:00
|
|
|
|
}
|
|
|
|
|
|
return Some(pattern);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// Phase 33-8: Level 2 - Pattern matching details
|
|
|
|
|
|
if self.debug_level >= 2 {
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] ❌ no pattern matched");
|
2025-11-27 02:58:38 +09:00
|
|
|
|
}
|
|
|
|
|
|
None
|
|
|
|
|
|
}
|
2025-11-27 03:28:32 +09:00
|
|
|
|
|
|
|
|
|
|
/// simple パターン: if cond { return 1 } else { return 2 }
|
2025-11-27 17:05:46 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// Phase 33-9.2: 実用MIR対応 - 副作用なし命令(Const/Copy)を許容
|
|
|
|
|
|
/// - 旧: Return のみ(instructions empty)
|
|
|
|
|
|
/// - 新: Const/Copy → Return を許容(実MIRパターン)
|
2025-11-27 03:28:32 +09:00
|
|
|
|
fn try_match_simple_pattern(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
branch: &IfBranch,
|
|
|
|
|
|
then_block: &crate::mir::BasicBlock,
|
|
|
|
|
|
else_block: &crate::mir::BasicBlock,
|
|
|
|
|
|
) -> Option<IfPattern> {
|
|
|
|
|
|
// then ブロックが Return だけか確認
|
|
|
|
|
|
let then_val = match then_block.terminator.as_ref()? {
|
|
|
|
|
|
MirInstruction::Return { value: Some(v) } => *v,
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// else ブロックが Return だけか確認
|
|
|
|
|
|
let else_val = match else_block.terminator.as_ref()? {
|
|
|
|
|
|
MirInstruction::Return { value: Some(v) } => *v,
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// Phase 33-9.2: 副作用なし命令(Const/Copy)のみを許容
|
|
|
|
|
|
// - ユニットテスト(empty)も通過(空配列 → all() = true)
|
|
|
|
|
|
// - 実用MIR(const + ret)も通過
|
|
|
|
|
|
if !self.is_side_effect_free(&then_block.instructions)
|
|
|
|
|
|
|| !self.is_side_effect_free(&else_block.instructions)
|
|
|
|
|
|
{
|
2025-11-27 03:28:32 +09:00
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Some(IfPattern {
|
|
|
|
|
|
pattern_type: IfPatternType::Simple,
|
|
|
|
|
|
cond: branch.cond,
|
|
|
|
|
|
then_val,
|
|
|
|
|
|
else_val,
|
|
|
|
|
|
dst: None,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
/// Phase 33-9.2: 副作用なし命令判定ヘルパー
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Const/Copy のみを許容(分岐・call・書き込み等は除外)
|
|
|
|
|
|
fn is_side_effect_free(&self, instructions: &[MirInstruction]) -> bool {
|
|
|
|
|
|
instructions.iter().all(|inst| {
|
|
|
|
|
|
matches!(
|
|
|
|
|
|
inst,
|
|
|
|
|
|
MirInstruction::Const { .. } | MirInstruction::Copy { .. }
|
|
|
|
|
|
)
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Phase 33-10: Jump pattern 検出ヘルパー
|
|
|
|
|
|
///
|
|
|
|
|
|
/// then/else 両方が Jump で終わり、同じ merge block に飛んでいる場合、
|
|
|
|
|
|
/// その merge block IDを返す
|
|
|
|
|
|
fn get_merge_block_if_jump_pattern(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
_branch: &IfBranch,
|
|
|
|
|
|
then_block: &crate::mir::BasicBlock,
|
|
|
|
|
|
else_block: &crate::mir::BasicBlock,
|
|
|
|
|
|
) -> Option<BasicBlockId> {
|
|
|
|
|
|
// then が Jump で終わるか確認
|
|
|
|
|
|
let then_target = match then_block.terminator.as_ref()? {
|
|
|
|
|
|
MirInstruction::Jump { target } => *target,
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// else が Jump で終わるか確認
|
|
|
|
|
|
let else_target = match else_block.terminator.as_ref()? {
|
|
|
|
|
|
MirInstruction::Jump { target } => *target,
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 両方が同じ merge block に飛んでいるか確認
|
|
|
|
|
|
if then_target == else_target {
|
|
|
|
|
|
Some(then_target)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
None
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
/// local パターン: if cond { x = a } else { x = b }; return x
|
2025-11-27 17:05:46 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// Phase 33-10: 実用MIR対応 - Const命令を許容
|
|
|
|
|
|
/// - 旧: Copy命令のみ(ユニットテスト想定)
|
|
|
|
|
|
/// - 新: Const/Copy命令を許容(実MIR対応、Simple patternと同じ修正)
|
2025-11-27 03:28:32 +09:00
|
|
|
|
fn try_match_local_pattern(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
func: &MirFunction,
|
|
|
|
|
|
branch: &IfBranch,
|
|
|
|
|
|
then_block: &crate::mir::BasicBlock,
|
|
|
|
|
|
else_block: &crate::mir::BasicBlock,
|
|
|
|
|
|
) -> Option<IfPattern> {
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// Phase 33-10: 副作用なし命令のみを許容
|
|
|
|
|
|
if !self.is_side_effect_free(&then_block.instructions) {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// then ブロックの最後の値を取得
|
|
|
|
|
|
// Phase 33-10: Const命令も許容(実MIR対応)
|
|
|
|
|
|
let (dst_then, val_then) = if then_block.instructions.len() == 1 {
|
|
|
|
|
|
match &then_block.instructions[0] {
|
|
|
|
|
|
MirInstruction::Copy { dst, src } => (*dst, *src),
|
|
|
|
|
|
MirInstruction::Const { dst, .. } => (*dst, *dst), // Constの場合、dst自身が値
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return None;
|
2025-11-27 03:28:32 +09:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// then ブロックが Jump で終わるか確認
|
|
|
|
|
|
let merge_block_id = match then_block.terminator.as_ref()? {
|
|
|
|
|
|
MirInstruction::Jump { target } => *target,
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// Phase 33-10: else ブロックも副作用なし命令のみを許容
|
|
|
|
|
|
if !self.is_side_effect_free(&else_block.instructions) {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// else ブロックの最後の値を取得
|
|
|
|
|
|
let (dst_else, val_else) = if else_block.instructions.len() == 1 {
|
|
|
|
|
|
match &else_block.instructions[0] {
|
|
|
|
|
|
MirInstruction::Copy { dst, src } => (*dst, *src),
|
|
|
|
|
|
MirInstruction::Const { dst, .. } => (*dst, *dst), // Constの場合、dst自身が値
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return None;
|
2025-11-27 03:28:32 +09:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 代入先が同じ変数か確認
|
|
|
|
|
|
if dst_then != dst_else {
|
|
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// else ブロックも同じ merge ブロックに Jump するか確認
|
|
|
|
|
|
let else_merge = match else_block.terminator.as_ref()? {
|
|
|
|
|
|
MirInstruction::Jump { target } => *target,
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if merge_block_id != else_merge {
|
|
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// merge ブロックが「return dst」だけか確認
|
|
|
|
|
|
let merge_block = func.blocks.get(&merge_block_id)?;
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// Phase 33-10: PHIチェックは find_if_pattern() で早期実行済み
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
match merge_block.terminator.as_ref()? {
|
2025-11-28 17:42:19 +09:00
|
|
|
|
MirInstruction::Return { value: Some(v) } if *v == dst_then => {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
// OK
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if !merge_block.instructions.is_empty() {
|
|
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Some(IfPattern {
|
|
|
|
|
|
pattern_type: IfPatternType::Local,
|
|
|
|
|
|
cond: branch.cond,
|
|
|
|
|
|
then_val: val_then,
|
|
|
|
|
|
else_val: val_else,
|
|
|
|
|
|
dst: Some(dst_then),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-11-27 02:58:38 +09:00
|
|
|
|
}
|
feat(joinir): Phase 63-4 infer_type_from_phi degradation design
Phase 63-4: infer_type_from_phi を『JoinIR 型ヒント優先+従来ロジックフォールバック』に縮退する仕様を設計(実装は Phase 63-5+)
## Changes
### Documentation Updates
- **README.md**: Added complete Phase 63-4 design (63-4.1 through 63-4.5)
- 63-4.1: Current state analysis (definition location, callsites, role, JoinIR preparation)
- 63-4.2: Degradation spec (type_hint priority + fallback pattern)
- 63-4.3: Representative cases and A/B testing strategy (P1/P2/P3)
- 63-4.4: Deletion conditions (5 conditions, current: 2/5 = 40%)
- 63-4.5: Phase 63-5 handoff (infer_type_from_phi_with_hint() implementation tasks)
- **PHI_BOX_INVENTORY.md**: Updated if_phi.rs entry with Phase 63-4 deletion plan
- Added: "Phase 63-4完了: infer_type_from_phi の JoinIR type_hint 優先への縮退案を設計(実装は Phase 63-5+)"
- **CURRENT_TASK.md**: Added Phase 63-4 section with summary of design work
## Design Highlights
### Degradation Pattern
```rust
pub fn infer_type_from_phi_with_hint(
function: &MirFunction,
ret_val: ValueId,
types: &BTreeMap<ValueId, MirType>,
type_hint: Option<MirType>,
) -> Option<MirType> {
if let Some(hint) = type_hint {
return Some(hint); // Route B: JoinIR priority (SSOT)
}
infer_type_from_phi(function, ret_val, types) // Route A: Fallback
}
```
### Representative Cases
- **P1**: IfSelectTest.simple/local (Phase 63-5 target)
- **P2**: read_quoted_from (Phase 63-6+ target)
- **P3**: MethodCall/Box constructors (Phase 64+ expansion)
### Deletion Conditions (2/5 achieved)
1. ✅ JoinIR has type_hint field (Phase 63-3)
2. ✅ Type hints populated for representative cases (Phase 63-2)
3. ⏳ Degraded to type_hint priority (Phase 63-5)
4. ⏳ P1 cases determined by type_hint only (Phase 63-5)
5. ⏳ All functions use type hints (Phase 64+)
## Files Changed
- docs/private/roadmap2/phases/phase-63-joinir-type-info/README.md
- docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md
- CURRENT_TASK.md
## Next Steps
Phase 63-5: Implement degradation for P1 cases (IfSelectTest.simple/local)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 17:58:06 +09:00
|
|
|
|
|
2025-12-04 22:33:56 +09:00
|
|
|
|
// Phase 185: infer_type_from_mir_pattern() moved to common.rs
|
|
|
|
|
|
use super::common::infer_type_from_mir_pattern;
|