refactor(joinir): Phase 27.10 - CFG sanity checks + dispatcher pattern 共通化

- common.rs 新規作成(162行):
  - CFG sanity check helpers: ensure_entry_has_succs, has_const_int, has_const_string, has_string_method, has_binop
  - Logging helper: log_fallback
  - Dispatcher: dispatch_lowering
- skip_ws.rs: CFG checks (-25行) + dispatcher (-2行) = -27行削減
- funcscanner_trim.rs: CFG checks (-25行) + dispatcher (-4行) = -29行削減
- mod.rs: pub mod common 追加

設計原則:
- 軽量パターンマッチング(命令の存在確認のみ)
- Graceful degradation(予期しない構造で即座にfallback)
- DRY原則(重複コード1箇所に集約)

🎉 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-23 22:51:30 +09:00
parent c1aa3c8c2b
commit ff9ea58e59
4 changed files with 237 additions and 27 deletions

View File

@ -50,7 +50,20 @@ use crate::mir::join_ir::{
LoopExitShape, LoopHeaderShape, MirLikeInst,
};
/// Phase 27.9: Toggle dispatcher for trim lowering
/// - Default: handwritten lowering
/// - NYASH_JOINIR_LOWER_FROM_MIR=1: MIR-based lowering
pub fn lower_funcscanner_trim_to_joinir(module: &crate::mir::MirModule) -> Option<JoinModule> {
super::common::dispatch_lowering(
"trim",
module,
lower_trim_from_mir,
lower_trim_handwritten,
)
}
/// Phase 27.1-27.7: Handwritten JoinIR lowering for FuncScannerBox.trim/1
fn lower_trim_handwritten(module: &crate::mir::MirModule) -> Option<JoinModule> {
// Step 1: "FuncScannerBox.trim/1" を探す
let target_func = module.functions.get("FuncScannerBox.trim/1")?;
@ -495,3 +508,47 @@ pub fn lower_funcscanner_trim_to_joinir(module: &crate::mir::MirModule) -> Optio
Some(join_module)
}
/// Phase 27.9: MIR-based lowering for FuncScannerBox.trim/1
/// - Lightweight CFG sanity checks
/// - Fallback to handwritten if MIR structure is unexpected
fn lower_trim_from_mir(module: &crate::mir::MirModule) -> Option<JoinModule> {
use crate::mir::query::MirQueryBox;
use crate::mir::BinaryOp;
use super::common::{ensure_entry_has_succs, has_const_string, has_string_method, has_binop, log_fallback};
// Step 1: "FuncScannerBox.trim/1" を探す
let target_func = module.functions.get("FuncScannerBox.trim/1")?;
eprintln!("[joinir/trim/mir] Found FuncScannerBox.trim/1 (MIR-based lowering)");
eprintln!("[joinir/trim/mir] MIR blocks: {}", target_func.blocks.len());
// Phase 27.10: Lightweight CFG sanity checks using common utilities
let query = MirQueryBox::new(target_func);
let entry_id = target_func.entry_block;
// Check 1: Entry block has at least 1 successor
if !ensure_entry_has_succs(&query, entry_id) {
log_fallback("trim", "entry has no successors");
return lower_trim_handwritten(module);
}
// Check 2: Entry block contains expected patterns
// - Const("") for string coercion
// - BoxCall(String.length)
// - BinOp(Add) for "" + s
if !has_const_string(&query, entry_id, "") ||
!has_string_method(&query, entry_id, "length") ||
!has_binop(&query, entry_id, BinaryOp::Add)
{
log_fallback("trim", "entry block missing expected patterns (Const(\"\"), String.length, or BinOp(Add))");
return lower_trim_handwritten(module);
}
eprintln!("[joinir/trim/mir] CFG sanity checks passed ✅");
// Phase 27.9: Generate JoinIR (equivalent to handwritten version)
// For now, use the same structure as handwritten version
// TODO: Full MIR-based construction in future phases
lower_trim_handwritten(module)
}