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

@ -41,7 +41,7 @@
use crate::mir::ValueId;
use crate::mir::join_ir::{
env_flag_is_1, BinOpKind, CompareOp, ConstValue, JoinContId, JoinFuncId, JoinFunction,
BinOpKind, CompareOp, ConstValue, JoinContId, JoinFuncId, JoinFunction,
JoinInst, JoinModule, LoopExitShape, LoopHeaderShape, MirLikeInst,
};
@ -229,8 +229,8 @@ fn lower_skip_ws_handwritten(module: &crate::mir::MirModule) -> Option<JoinModul
/// ## 実装状況:
/// - Phase 27.8: 基本実装MirQuery を使用した MIR 解析)
fn lower_skip_ws_from_mir(module: &crate::mir::MirModule) -> Option<JoinModule> {
use crate::mir::query::{MirQuery, MirQueryBox};
use crate::mir::MirInstruction;
use crate::mir::query::MirQueryBox;
use super::common::{ensure_entry_has_succs, has_const_int, has_string_method, log_fallback};
// Step 1: "Main.skip/1" を探す
let target_func = module.functions.get("Main.skip/1")?;
@ -245,33 +245,23 @@ fn lower_skip_ws_from_mir(module: &crate::mir::MirModule) -> Option<JoinModule>
// 簡易チェック: ブロック数が最低限あるか確認
if target_func.blocks.len() < 3 {
eprintln!("[joinir/skip_ws/mir] insufficient blocks ({}), falling back", target_func.blocks.len());
log_fallback("skip_ws", &format!("insufficient blocks ({})", target_func.blocks.len()));
return lower_skip_ws_handwritten(module);
}
// Phase 27.8-4: Lightweight CFG sanity checks
// MirQueryBox を使ってパターンマッチング
// 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
let entry_succs = query.succs(entry_id);
if entry_succs.is_empty() {
eprintln!("[joinir/skip_ws/mir] unexpected MIR shape: entry has no successors, falling back to handwritten");
if !ensure_entry_has_succs(&query, entry_id) {
log_fallback("skip_ws", "entry has no successors");
return lower_skip_ws_handwritten(module);
}
// Check 2: First block contains Const(0) and BoxCall(String.length)
let entry_insts = query.insts_in_block(entry_id);
let has_const_0 = entry_insts.iter().any(|inst| {
matches!(inst, MirInstruction::Const { value: crate::mir::ConstValue::Integer(0), .. })
});
let has_string_length = entry_insts.iter().any(|inst| {
matches!(inst, MirInstruction::BoxCall { method, .. } if method == "length")
});
if !has_const_0 || !has_string_length {
eprintln!("[joinir/skip_ws/mir] unexpected MIR shape: entry block missing Const(0) or String.length, falling back to handwritten");
// Check 2: Entry block contains Const(0) and BoxCall(String.length)
if !has_const_int(&query, entry_id, 0) || !has_string_method(&query, entry_id, "length") {
log_fallback("skip_ws", "entry block missing Const(0) or String.length");
return lower_skip_ws_handwritten(module);
}
@ -435,11 +425,10 @@ fn lower_skip_ws_from_mir(module: &crate::mir::MirModule) -> Option<JoinModule>
/// NYASH_JOINIR_LOWER_FROM_MIR=1 ./target/release/hakorune program.hako
/// ```
pub fn lower_skip_ws_to_joinir(module: &crate::mir::MirModule) -> Option<JoinModule> {
if env_flag_is_1("NYASH_JOINIR_LOWER_FROM_MIR") {
eprintln!("[joinir/skip_ws] Using MIR-based lowering (NYASH_JOINIR_LOWER_FROM_MIR=1)");
lower_skip_ws_from_mir(module)
} else {
eprintln!("[joinir/skip_ws] Using handwritten lowering (default)");
lower_skip_ws_handwritten(module)
}
super::common::dispatch_lowering(
"skip_ws",
module,
lower_skip_ws_from_mir,
lower_skip_ws_handwritten,
)
}