feat(joinir): Phase 188.3-P3.3 - Pattern6 continuation generation + Call callee fix

Phase 3-3 完了: 4関数モデル JoinIR 生成
- nested_loop_minimal.rs (337行, 新規): 4関数モデル実装
  - main(): エントリーポイント
  - loop_step(i, sum): outer loop header
  - inner_step(j, i_outer, sum): inner loop (tail recursion)
  - k_inner_exit(i, sum): outer continuation after inner loop
  - k_exit(sum): 最終 exit
- pattern6_nested_minimal.rs: lowering pipeline 実装
  - boundary 構築 (continuation_func_ids 設定)
  - JoinIRConversionPipeline 呼び出し
- instruction_rewriter.rs: latch incoming 拡張
  - continuation→header 呼び出し対応

Call callee 修正:
- call_generator.rs: callee フィールドを Callee::Global に設定
- joinir_block_converter.rs: emit_call_pair 使用に統一

smoke test 追加:
- phase1883_nested_minimal_vm.sh (integration)

既知の問題 (次タスク):
- ValueId(104) undefined: PHI/merge 問題
- JoinIR 関数パラメータの MIR マッピングが不完全

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-27 06:51:43 +09:00
parent c6ffc06660
commit d0527bcc2a
7 changed files with 550 additions and 19 deletions

View File

@ -100,18 +100,112 @@ pub(crate) fn can_lower(_builder: &MirBuilder, ctx: &LoopPatternContext) -> bool
/// Lower Pattern6 (NestedLoopMinimal) to MIR
///
/// Phase 188.3: Full implementation with continuation generation
/// Phase 188.3 P1: Full implementation with JoinIR pipeline
pub(crate) fn lower(
_builder: &mut MirBuilder,
builder: &mut MirBuilder,
ctx: &LoopPatternContext,
) -> Result<Option<ValueId>, String> {
use super::super::trace;
// Phase 3-1: Extract inner loop AST (validate exactly 1 inner loop)
let inner_ast = extract_inner_loop_ast(ctx)?;
let _inner_ast = extract_inner_loop_ast(ctx)?;
// Phase 3-2: Validate strict mode constraints (Fail-Fast)
validate_strict_mode(inner_ast, ctx)?;
validate_strict_mode(_inner_ast, ctx)?;
// Phase 3-3 stub - full implementation next
// TODO: Implement continuation generation (outer_step, inner_step, k_inner_exit)
Err("[Pattern6] Nested loop lowering not yet implemented (Phase 3-3 pending)".to_string())
// Phase 3-3: Full implementation with JoinIR pipeline
trace::trace().debug("pattern6", "Calling Pattern 6 nested loop minimal lowerer");
// Build preprocessing context - Pattern6 shares Pattern1's infrastructure
use super::pattern_pipeline::{build_pattern_context, PatternVariant};
let pattern_ctx = build_pattern_context(builder, ctx.condition, ctx.body, PatternVariant::Pattern1)?;
trace::trace().varmap("pattern6_start", &builder.variable_ctx.variable_map);
// Create JoinValueSpace for unified ValueId allocation
use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
let mut join_value_space = JoinValueSpace::new();
// Call Pattern 6 lowerer with preprocessed scope
use crate::mir::join_ir::lowering::nested_loop_minimal::lower_nested_loop_minimal;
let join_module = match lower_nested_loop_minimal(pattern_ctx.loop_scope, &mut join_value_space) {
Some(module) => module,
None => {
trace::trace().debug("pattern6", "Pattern 6 lowerer returned None");
return Ok(None);
}
};
// Create boundary from context
// Phase 188.3: Critical - must include continuation_func_ids to prevent merge misdetection
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
use crate::mir::join_ir::lowering::inline_boundary::LoopExitBinding;
use crate::mir::join_ir::lowering::join_value_space::PARAM_MIN;
use crate::mir::join_ir::lowering::JoinInlineBoundaryBuilder;
use crate::mir::join_ir::lowering::nested_loop_minimal::{INNER_STEP, K_INNER_EXIT};
// Extract k_exit's parameter ValueId from join_module
let k_exit_func = join_module.require_function("k_exit", "Pattern 6");
let sum_exit_value = k_exit_func
.params
.first()
.copied()
.expect("k_exit must have parameter for exit value (sum)");
// Phase 188.3: Extract variables from variable_map
let sum_var_id = builder
.variable_ctx
.variable_map
.get("sum")
.copied()
.ok_or_else(|| "[Pattern6] sum variable not found in variable_map".to_string())?;
let i_var_id = pattern_ctx.loop_var_id;
// Create exit binding for sum (the final return value)
let sum_exit_binding = LoopExitBinding {
carrier_name: "sum".to_string(),
join_exit_value: sum_exit_value,
host_slot: sum_var_id,
role: CarrierRole::LoopState,
};
// Phase 188.3 CRITICAL: Include continuation_func_ids to prevent merge from
// selecting inner_step as loop header
use std::collections::BTreeSet;
let continuation_funcs = BTreeSet::from([
"k_exit".to_string(),
K_INNER_EXIT.to_string(),
INNER_STEP.to_string(),
]);
let boundary = JoinInlineBoundaryBuilder::new()
.with_inputs(
vec![ValueId(PARAM_MIN), ValueId(PARAM_MIN + 1)], // main(i0, sum0)
vec![i_var_id, sum_var_id], // host variables
)
.with_exit_bindings(vec![sum_exit_binding])
.with_loop_var_name(Some(pattern_ctx.loop_var_name.clone())) // Phase 188.3: Enables header PHI for 'i'
.with_continuation_funcs(continuation_funcs)
.build();
// Use JoinIRConversionPipeline for unified conversion flow
use super::conversion_pipeline::JoinIRConversionPipeline;
let _ = JoinIRConversionPipeline::execute(
builder,
join_module,
Some(&boundary),
"pattern6",
ctx.debug,
)?;
// Return Void (loops don't produce values)
let void_val = crate::mir::builder::emission::constant::emit_void(builder);
trace::trace().debug(
"pattern6",
&format!("Nested loop complete, returning Void {:?}", void_val),
);
Ok(Some(void_val))
}