Phase 33-2: JoinInst::Select implementation + minimal If JoinIR lowering
Implementation:
- Add JoinInst::Select variant to JoinIR schema
- Implement Select execution in JoinIR Runner (Bool/Int cond support)
- Add Select handling in JoinIR→MIR Bridge (4-block structure)
- Create test cases (joinir_if_select_simple/local.hako)
- Add dev toggle NYASH_JOINIR_IF_SELECT=1
- Create lowering infrastructure (if_select.rs, stub for Phase 33-3)
Tests:
- 3/3 unit tests pass (test_select_true/false/int_cond)
- Integration tests pass (RC: 0)
- A/B execution verified (existing if_phi vs JoinIR Select)
Files changed:
- New: apps/tests/joinir_if_select_{simple,local}.hako
- New: src/mir/join_ir/lowering/if_select.rs
- Modified: src/mir/join_ir/{mod,json,runner,vm_bridge}.rs
- Modified: src/config/env.rs (joinir_if_select_enabled)
- Modified: docs/reference/environment-variables.md
Phase 33-3 ready: MIR pattern recognition + auto-lowering pending
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -108,6 +108,26 @@ fn execute_function(
|
||||
};
|
||||
return Ok(ret);
|
||||
}
|
||||
// Phase 33: Select instruction execution
|
||||
JoinInst::Select { dst, cond, then_val, else_val } => {
|
||||
// 1. Evaluate cond (Bool or Int)
|
||||
let cond_value = read_var(&locals, *cond)?;
|
||||
let cond_bool = match cond_value {
|
||||
JoinValue::Bool(b) => b,
|
||||
JoinValue::Int(i) => i != 0, // Int も許す(0=false, それ以外=true)
|
||||
_ => return Err(JoinRuntimeError::new(format!(
|
||||
"Select: cond must be Bool or Int, got {:?}", cond_value
|
||||
))),
|
||||
};
|
||||
|
||||
// 2. Select then_val or else_val
|
||||
let selected_id = if cond_bool { *then_val } else { *else_val };
|
||||
let selected_value = read_var(&locals, selected_id)?;
|
||||
|
||||
// 3. Write to dst
|
||||
locals.insert(*dst, selected_value);
|
||||
ip += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,3 +239,157 @@ fn as_bool(value: &JoinValue) -> Result<bool, JoinRuntimeError> {
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mir::join_ir::{ConstValue, JoinFunction, JoinModule};
|
||||
use crate::mir::ValueId;
|
||||
use crate::backend::mir_interpreter::MirInterpreter;
|
||||
|
||||
#[test]
|
||||
fn test_select_true() {
|
||||
// let result = if true { 1 } else { 2 }
|
||||
// expected: result == 1
|
||||
let mut module = JoinModule::new();
|
||||
let mut func = JoinFunction::new(JoinFuncId::new(0), "test_func".to_string(), vec![]);
|
||||
|
||||
let v_cond = ValueId(1);
|
||||
let v_then = ValueId(2);
|
||||
let v_else = ValueId(3);
|
||||
let v_result = ValueId(4);
|
||||
|
||||
// const v1 = true
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: v_cond,
|
||||
value: ConstValue::Bool(true),
|
||||
}));
|
||||
|
||||
// const v2 = 1
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: v_then,
|
||||
value: ConstValue::Integer(1),
|
||||
}));
|
||||
|
||||
// const v3 = 2
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: v_else,
|
||||
value: ConstValue::Integer(2),
|
||||
}));
|
||||
|
||||
// select v4 = v1 ? v2 : v3
|
||||
func.body.push(JoinInst::Select {
|
||||
dst: v_result,
|
||||
cond: v_cond,
|
||||
then_val: v_then,
|
||||
else_val: v_else,
|
||||
});
|
||||
|
||||
// return v4
|
||||
func.body.push(JoinInst::Ret { value: Some(v_result) });
|
||||
|
||||
module.add_function(func);
|
||||
|
||||
let mut vm = MirInterpreter::new();
|
||||
let result = run_joinir_function(&mut vm, &module, JoinFuncId::new(0), &[]).unwrap();
|
||||
|
||||
assert_eq!(result, JoinValue::Int(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_select_false() {
|
||||
// let result = if false { 1 } else { 2 }
|
||||
// expected: result == 2
|
||||
let mut module = JoinModule::new();
|
||||
let mut func = JoinFunction::new(JoinFuncId::new(0), "test_func".to_string(), vec![]);
|
||||
|
||||
let v_cond = ValueId(1);
|
||||
let v_then = ValueId(2);
|
||||
let v_else = ValueId(3);
|
||||
let v_result = ValueId(4);
|
||||
|
||||
// const v1 = false
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: v_cond,
|
||||
value: ConstValue::Bool(false),
|
||||
}));
|
||||
|
||||
// const v2 = 1
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: v_then,
|
||||
value: ConstValue::Integer(1),
|
||||
}));
|
||||
|
||||
// const v3 = 2
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: v_else,
|
||||
value: ConstValue::Integer(2),
|
||||
}));
|
||||
|
||||
// select v4 = v1 ? v2 : v3
|
||||
func.body.push(JoinInst::Select {
|
||||
dst: v_result,
|
||||
cond: v_cond,
|
||||
then_val: v_then,
|
||||
else_val: v_else,
|
||||
});
|
||||
|
||||
// return v4
|
||||
func.body.push(JoinInst::Ret { value: Some(v_result) });
|
||||
|
||||
module.add_function(func);
|
||||
|
||||
let mut vm = MirInterpreter::new();
|
||||
let result = run_joinir_function(&mut vm, &module, JoinFuncId::new(0), &[]).unwrap();
|
||||
|
||||
assert_eq!(result, JoinValue::Int(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_select_int_cond() {
|
||||
// cond=Int(0) → false、Int(1) → true
|
||||
let mut module = JoinModule::new();
|
||||
let mut func = JoinFunction::new(JoinFuncId::new(0), "test_func".to_string(), vec![]);
|
||||
|
||||
let v_cond = ValueId(1);
|
||||
let v_then = ValueId(2);
|
||||
let v_else = ValueId(3);
|
||||
let v_result = ValueId(4);
|
||||
|
||||
// const v1 = 0 (treated as false)
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: v_cond,
|
||||
value: ConstValue::Integer(0),
|
||||
}));
|
||||
|
||||
// const v2 = 100
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: v_then,
|
||||
value: ConstValue::Integer(100),
|
||||
}));
|
||||
|
||||
// const v3 = 200
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: v_else,
|
||||
value: ConstValue::Integer(200),
|
||||
}));
|
||||
|
||||
// select v4 = v1 ? v2 : v3
|
||||
func.body.push(JoinInst::Select {
|
||||
dst: v_result,
|
||||
cond: v_cond,
|
||||
then_val: v_then,
|
||||
else_val: v_else,
|
||||
});
|
||||
|
||||
// return v4
|
||||
func.body.push(JoinInst::Ret { value: Some(v_result) });
|
||||
|
||||
module.add_function(func);
|
||||
|
||||
let mut vm = MirInterpreter::new();
|
||||
let result = run_joinir_function(&mut vm, &module, JoinFuncId::new(0), &[]).unwrap();
|
||||
|
||||
assert_eq!(result, JoinValue::Int(200)); // 0 is false, so should select else
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user