feat(joinir): Phase 27.11.1 - skip_ws.rs Shared Builder Pattern 完了
## 成果 - **コード削減**: 444行 → 310行 (134行削除、30%削減) - **重複コード根絶**: handwritten版とMIR版の重複JoinIR生成を統一 - **テスト結果**: - Baseline (toggle OFF): 380 passed - MIR-based (toggle ON): 385 passed ✅ (5件改善!) ## 実装内容 1. `lower_skip_ws_handwritten()` → `build_skip_ws_joinir()` にリネーム - 共通JoinIRビルダー化 2. 新しい thin wrapper `lower_skip_ws_handwritten()` を作成 3. `lower_skip_ws_from_mir()` の重複コード (140行) を削除 - CFGチェック後に `build_skip_ws_joinir()` を呼び出す構造に変更 ## 設計パターン - **Shared Builder Pattern**: funcscanner_trim.rs と同じパターン適用 - **CFG Sanity Checks**: MIR解析は軽量パターンマッチのみ - **Graceful Degradation**: CFGチェック失敗時は自動フォールバック Phase 27.11シリーズ 100%完了! 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -45,16 +45,17 @@ use crate::mir::join_ir::{
|
||||
JoinInst, JoinModule, LoopExitShape, LoopHeaderShape, MirLikeInst,
|
||||
};
|
||||
|
||||
/// Phase 27.8: Main.skip/1 の JoinIR lowering(手書き版)
|
||||
/// Phase 27.11.1: Common JoinIR builder for Main.skip/1
|
||||
///
|
||||
/// Phase 27.1-27.7 で実装された hand-written JoinIR 生成。
|
||||
/// Phase 27.8 以降は `lower_skip_ws_from_mir()` に移行予定。
|
||||
fn lower_skip_ws_handwritten(module: &crate::mir::MirModule) -> Option<JoinModule> {
|
||||
/// This function generates the JoinIR for skip/1, shared by both:
|
||||
/// - lower_skip_ws_handwritten (always uses this)
|
||||
/// - lower_skip_ws_from_mir (uses this after CFG sanity checks pass)
|
||||
fn build_skip_ws_joinir(module: &crate::mir::MirModule) -> Option<JoinModule> {
|
||||
// Step 1: "Main.skip/1" を探す
|
||||
let target_func = module.functions.get("Main.skip/1")?;
|
||||
|
||||
eprintln!("[joinir/skip_ws] Found Main.skip/1");
|
||||
eprintln!("[joinir/skip_ws] MIR blocks: {}", target_func.blocks.len());
|
||||
eprintln!("[joinir/skip_ws/build] Found Main.skip/1");
|
||||
eprintln!("[joinir/skip_ws/build] MIR blocks: {}", target_func.blocks.len());
|
||||
|
||||
// Step 2: JoinModule を構築
|
||||
let mut join_module = JoinModule::new();
|
||||
@ -267,144 +268,19 @@ fn lower_skip_ws_from_mir(module: &crate::mir::MirModule) -> Option<JoinModule>
|
||||
|
||||
eprintln!("[joinir/skip_ws/mir] CFG sanity checks passed ✅");
|
||||
|
||||
// JoinIR の ValueId は手書き版と同じレンジを使い、既存テストと互換にする
|
||||
let skip_id = JoinFuncId::new(0);
|
||||
let loop_step_id = JoinFuncId::new(1);
|
||||
// Phase 27.11.1: Generate JoinIR using shared builder
|
||||
// CFG checks passed, so we can use build_skip_ws_joinir() directly
|
||||
eprintln!("[joinir/skip_ws/mir] Calling build_skip_ws_joinir() after CFG validation");
|
||||
return build_skip_ws_joinir(module);
|
||||
}
|
||||
|
||||
// -------- skip 関数(入口) --------
|
||||
let s_param = ValueId(3000);
|
||||
let mut skip_func = JoinFunction::new(skip_id, "skip".to_string(), vec![s_param]);
|
||||
|
||||
let i_init = ValueId(3001);
|
||||
let n = ValueId(3002);
|
||||
|
||||
// i_init = 0
|
||||
skip_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: i_init,
|
||||
value: ConstValue::Integer(0),
|
||||
}));
|
||||
|
||||
// n = s.length()
|
||||
skip_func.body.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(n),
|
||||
box_name: "StringBox".to_string(),
|
||||
method: "length".to_string(),
|
||||
args: vec![s_param],
|
||||
}));
|
||||
|
||||
// loop_step(s, i_init, n)
|
||||
skip_func.body.push(JoinInst::Call {
|
||||
func: loop_step_id,
|
||||
args: vec![s_param, i_init, n],
|
||||
k_next: None,
|
||||
dst: None,
|
||||
});
|
||||
|
||||
// -------- loop_step 関数 --------
|
||||
// Header 形: pinned = [s, n], carrier = [i]
|
||||
let s_loop = ValueId(4000); // pinned
|
||||
let i_loop = ValueId(4001); // carrier
|
||||
let n_loop = ValueId(4002); // pinned
|
||||
|
||||
let _header_shape = LoopHeaderShape::new_manual(vec![s_loop, n_loop], vec![i_loop]);
|
||||
let _exit_shape = LoopExitShape::new_manual(vec![i_loop]); // exit_args = [i]
|
||||
|
||||
let mut loop_step_func = JoinFunction::new(
|
||||
loop_step_id,
|
||||
"loop_step".to_string(),
|
||||
vec![s_loop, i_loop, n_loop],
|
||||
);
|
||||
|
||||
let cmp1_result = ValueId(4003);
|
||||
let ch = ValueId(4004);
|
||||
let cmp2_result = ValueId(4005);
|
||||
let i_plus_1 = ValueId(4006);
|
||||
let const_1 = ValueId(4007);
|
||||
let const_space = ValueId(4010);
|
||||
let bool_false = ValueId(4011);
|
||||
let cmp2_is_false = ValueId(4012);
|
||||
|
||||
// if i >= n { k_exit(i) }
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||
dst: cmp1_result,
|
||||
op: CompareOp::Ge,
|
||||
lhs: i_loop,
|
||||
rhs: n_loop,
|
||||
}));
|
||||
loop_step_func.body.push(JoinInst::Jump {
|
||||
cont: JoinContId::new(0),
|
||||
args: vec![i_loop],
|
||||
cond: Some(cmp1_result),
|
||||
});
|
||||
|
||||
// const 1
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: const_1,
|
||||
value: ConstValue::Integer(1),
|
||||
}));
|
||||
|
||||
// i_plus_1 = i + 1
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||
dst: i_plus_1,
|
||||
op: BinOpKind::Add,
|
||||
lhs: i_loop,
|
||||
rhs: const_1,
|
||||
}));
|
||||
|
||||
// ch = s.substring(i, i+1)
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(ch),
|
||||
box_name: "StringBox".to_string(),
|
||||
method: "substring".to_string(),
|
||||
args: vec![s_loop, i_loop, i_plus_1],
|
||||
}));
|
||||
|
||||
// cmp2 = (ch == " ")
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: const_space,
|
||||
value: ConstValue::String(" ".to_string()),
|
||||
}));
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||
dst: cmp2_result,
|
||||
op: CompareOp::Eq,
|
||||
lhs: ch,
|
||||
rhs: const_space,
|
||||
}));
|
||||
|
||||
// cmp2_is_false = (cmp2 == false)
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: bool_false,
|
||||
value: ConstValue::Bool(false),
|
||||
}));
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||
dst: cmp2_is_false,
|
||||
op: CompareOp::Eq,
|
||||
lhs: cmp2_result,
|
||||
rhs: bool_false,
|
||||
}));
|
||||
|
||||
// if ch != " " { k_exit(i) }
|
||||
loop_step_func.body.push(JoinInst::Jump {
|
||||
cont: JoinContId::new(1),
|
||||
args: vec![i_loop],
|
||||
cond: Some(cmp2_is_false),
|
||||
});
|
||||
|
||||
// continue: loop_step(s, i+1, n)
|
||||
loop_step_func.body.push(JoinInst::Call {
|
||||
func: loop_step_id,
|
||||
args: vec![s_loop, i_plus_1, n_loop],
|
||||
k_next: None,
|
||||
dst: None,
|
||||
});
|
||||
|
||||
// -------- JoinModule 完成 --------
|
||||
let mut join_module = JoinModule::new();
|
||||
join_module.entry = Some(skip_id);
|
||||
join_module.add_function(skip_func);
|
||||
join_module.add_function(loop_step_func);
|
||||
|
||||
Some(join_module)
|
||||
/// Phase 27.11.1: Handwritten lowering wrapper for Main.skip/1
|
||||
///
|
||||
/// This is a thin wrapper that calls the shared build_skip_ws_joinir() function.
|
||||
/// Maintains the handwritten lowering path as the baseline reference.
|
||||
fn lower_skip_ws_handwritten(module: &crate::mir::MirModule) -> Option<JoinModule> {
|
||||
eprintln!("[joinir/skip_ws/handwritten] Using handwritten lowering path");
|
||||
build_skip_ws_joinir(module)
|
||||
}
|
||||
|
||||
/// Phase 27.8: Main.skip/1 の JoinIR lowering(トグル対応ディスパッチャー)
|
||||
|
||||
Reference in New Issue
Block a user