Files
hakorune/src/mir/builder/joinir_id_remapper.rs

483 lines
16 KiB
Rust

//! Phase 189: JoinIR ID Remapper - ValueId/BlockId ID空間変換の独立化
//!
//! 責務:
//! - ValueId/BlockId の ID割り当て
//! - JoinIR fragment → host MIR への ID変換
//! - 決定性を重視した実装
use crate::mir::{BasicBlock, BasicBlockId, MirInstruction, ValueId};
use std::collections::BTreeMap; // Phase 222.5-E: HashMap → BTreeMap for determinism
/// JoinIR ID space を host MIR ID space に変換する
pub struct JoinIrIdRemapper {
/// (func_name, old_block_id) → new_block_id のマッピング
/// Phase 222.5-E: HashMap → BTreeMap for determinism
block_map: BTreeMap<(String, BasicBlockId), BasicBlockId>,
/// old_value_id → new_value_id のマッピング
/// Phase 222.5-E: HashMap → BTreeMap for determinism
value_map: BTreeMap<ValueId, ValueId>,
}
impl JoinIrIdRemapper {
pub fn new() -> Self {
Self {
// Phase 222.5-E: HashMap → BTreeMap for determinism
block_map: BTreeMap::new(),
value_map: BTreeMap::new(),
}
}
/// Block ID mapping を取得
pub fn get_block(&self, func_name: &str, old_id: BasicBlockId) -> Option<BasicBlockId> {
self.block_map
.get(&(func_name.to_string(), old_id))
.copied()
}
/// Value ID mapping を取得
pub fn get_value(&self, old_id: ValueId) -> Option<ValueId> {
self.value_map.get(&old_id).copied()
}
/// Block mapping を設定
pub fn set_block(&mut self, func_name: String, old_id: BasicBlockId, new_id: BasicBlockId) {
self.block_map.insert((func_name, old_id), new_id);
}
/// Value mapping を設定
pub fn set_value(&mut self, old_id: ValueId, new_id: ValueId) {
self.value_map.insert(old_id, new_id);
}
/// Block 内の ValueId を収集
pub fn collect_values_in_block(&self, block: &BasicBlock) -> Vec<ValueId> {
let mut values = Vec::new();
for inst in &block.instructions {
values.extend(self.collect_values_in_instruction(inst));
}
if let Some(ref term) = block.terminator {
values.extend(self.collect_values_in_instruction(term));
}
values
}
/// 命令内の ValueId を収集
pub fn collect_values_in_instruction(&self, inst: &MirInstruction) -> Vec<ValueId> {
use crate::mir::MirInstruction::*;
match inst {
Const { dst, .. } => vec![*dst],
UnaryOp { dst, operand, .. } => vec![*dst, *operand],
BinOp { dst, lhs, rhs, .. } => vec![*dst, *lhs, *rhs],
Compare { dst, lhs, rhs, .. } => vec![*dst, *lhs, *rhs],
Load { dst, ptr } => vec![*dst, *ptr],
Store { value, ptr } => vec![*value, *ptr],
Call {
dst, func, args, ..
} => {
let mut vals = vec![*func];
if let Some(d) = dst {
vals.push(*d);
}
vals.extend(args.iter().copied());
vals
}
BoxCall {
dst, box_val, args, ..
} => {
let mut vals = vec![*box_val];
if let Some(d) = dst {
vals.push(*d);
}
vals.extend(args.iter().copied());
vals
}
PluginInvoke {
dst, box_val, args, ..
} => {
let mut vals = vec![*box_val];
if let Some(d) = dst {
vals.push(*d);
}
vals.extend(args.iter().copied());
vals
}
Branch { condition, .. } => vec![*condition],
Return { value } => value.iter().copied().collect(),
Phi { dst, inputs, .. } => {
let mut vals = vec![*dst];
vals.extend(inputs.iter().map(|(_, v)| *v));
vals
}
Copy { dst, src } => vec![*dst, *src],
NewBox { dst, args, .. } => {
let mut vals = vec![*dst];
vals.extend(args.iter().copied());
vals
}
NewClosure {
dst, captures, me, ..
} => {
let mut vals = vec![*dst];
vals.extend(captures.iter().map(|(_, v)| *v));
if let Some(m) = me {
vals.push(*m);
}
vals
}
Print { value, .. } => vec![*value],
Debug { value, .. } => vec![*value],
DebugLog { values, .. } => values.clone(),
Throw { exception, .. } => vec![*exception],
Catch {
exception_value, ..
} => vec![*exception_value],
RefNew { dst, box_val } => vec![*dst, *box_val],
RefGet { dst, reference, .. } => vec![*dst, *reference],
RefSet {
reference, value, ..
} => vec![*reference, *value],
WeakNew { dst, box_val } => vec![*dst, *box_val],
WeakLoad { dst, weak_ref } => vec![*dst, *weak_ref],
WeakRef { dst, value, .. } => vec![*dst, *value],
BarrierRead { ptr } => vec![*ptr],
BarrierWrite { ptr } => vec![*ptr],
Barrier { ptr, .. } => vec![*ptr],
FutureNew { dst, value } => vec![*dst, *value],
FutureSet { future, value } => vec![*future, *value],
Await { dst, future } => vec![*dst, *future],
TypeCheck { dst, value, .. } => vec![*dst, *value],
Cast { dst, value, .. } => vec![*dst, *value],
TypeOp { dst, value, .. } => vec![*dst, *value],
ArrayGet { dst, array, index } => vec![*dst, *array, *index],
ArraySet {
array,
index,
value,
} => vec![*array, *index, *value],
Jump { .. } | Nop | Safepoint => vec![],
ExternCall { dst, args, .. } => {
let mut vals = Vec::new();
if let Some(d) = dst {
vals.push(*d);
}
vals.extend(args.iter().copied());
vals
}
}
}
/// 命令を新しい ID空間にリマップ
pub fn remap_instruction(&self, inst: &MirInstruction) -> MirInstruction {
use crate::mir::MirInstruction::*;
let remap = |v: ValueId| self.value_map.get(&v).copied().unwrap_or(v);
match inst {
Const { dst, value } => Const {
dst: remap(*dst),
value: value.clone(),
},
UnaryOp { dst, op, operand } => UnaryOp {
dst: remap(*dst),
op: *op,
operand: remap(*operand),
},
BinOp { dst, op, lhs, rhs } => BinOp {
dst: remap(*dst),
op: *op,
lhs: remap(*lhs),
rhs: remap(*rhs),
},
Compare { dst, op, lhs, rhs } => Compare {
dst: remap(*dst),
op: *op,
lhs: remap(*lhs),
rhs: remap(*rhs),
},
Load { dst, ptr } => Load {
dst: remap(*dst),
ptr: remap(*ptr),
},
Store { value, ptr } => Store {
value: remap(*value),
ptr: remap(*ptr),
},
Call {
dst,
func,
callee,
args,
effects,
} => Call {
dst: dst.map(remap),
func: remap(*func),
callee: callee.clone(),
args: args.iter().map(|&a| remap(a)).collect(),
effects: *effects,
},
BoxCall {
dst,
box_val,
method,
method_id,
args,
effects,
} => BoxCall {
dst: dst.map(remap),
box_val: remap(*box_val),
method: method.clone(),
method_id: *method_id,
args: args.iter().map(|&a| remap(a)).collect(),
effects: *effects,
},
PluginInvoke {
dst,
box_val,
method,
args,
effects,
} => PluginInvoke {
dst: dst.map(remap),
box_val: remap(*box_val),
method: method.clone(),
args: args.iter().map(|&a| remap(a)).collect(),
effects: *effects,
},
Copy { dst, src } => Copy {
dst: remap(*dst),
src: remap(*src),
},
NewBox {
dst,
box_type,
args,
} => NewBox {
dst: remap(*dst),
box_type: box_type.clone(),
args: args.iter().map(|&a| remap(a)).collect(),
},
NewClosure {
dst,
params,
body,
captures,
me,
} => NewClosure {
dst: remap(*dst),
params: params.clone(),
body: body.clone(),
captures: captures
.iter()
.map(|(n, v)| (n.clone(), remap(*v)))
.collect(),
me: me.map(remap),
},
Print { value, effects } => Print {
value: remap(*value),
effects: *effects,
},
Debug { value, message } => Debug {
value: remap(*value),
message: message.clone(),
},
DebugLog { message, values } => DebugLog {
message: message.clone(),
values: values.iter().map(|&v| remap(v)).collect(),
},
Throw { exception, effects } => Throw {
exception: remap(*exception),
effects: *effects,
},
Catch {
exception_type,
exception_value,
handler_bb,
} => Catch {
exception_type: exception_type.clone(),
exception_value: remap(*exception_value),
handler_bb: *handler_bb,
},
RefNew { dst, box_val } => RefNew {
dst: remap(*dst),
box_val: remap(*box_val),
},
RefGet {
dst,
reference,
field,
} => RefGet {
dst: remap(*dst),
reference: remap(*reference),
field: field.clone(),
},
RefSet {
reference,
field,
value,
} => RefSet {
reference: remap(*reference),
field: field.clone(),
value: remap(*value),
},
WeakNew { dst, box_val } => WeakNew {
dst: remap(*dst),
box_val: remap(*box_val),
},
WeakLoad { dst, weak_ref } => WeakLoad {
dst: remap(*dst),
weak_ref: remap(*weak_ref),
},
WeakRef { dst, op, value } => WeakRef {
dst: remap(*dst),
op: *op,
value: remap(*value),
},
BarrierRead { ptr } => BarrierRead { ptr: remap(*ptr) },
BarrierWrite { ptr } => BarrierWrite { ptr: remap(*ptr) },
Barrier { op, ptr } => Barrier {
op: *op,
ptr: remap(*ptr),
},
FutureNew { dst, value } => FutureNew {
dst: remap(*dst),
value: remap(*value),
},
FutureSet { future, value } => FutureSet {
future: remap(*future),
value: remap(*value),
},
Await { dst, future } => Await {
dst: remap(*dst),
future: remap(*future),
},
TypeCheck {
dst,
value,
expected_type,
} => TypeCheck {
dst: remap(*dst),
value: remap(*value),
expected_type: expected_type.clone(),
},
Cast {
dst,
value,
target_type,
} => Cast {
dst: remap(*dst),
value: remap(*value),
target_type: target_type.clone(),
},
TypeOp { dst, op, value, ty } => TypeOp {
dst: remap(*dst),
op: *op,
value: remap(*value),
ty: ty.clone(),
},
ArrayGet { dst, array, index } => ArrayGet {
dst: remap(*dst),
array: remap(*array),
index: remap(*index),
},
ArraySet {
array,
index,
value,
} => ArraySet {
array: remap(*array),
index: remap(*index),
value: remap(*value),
},
ExternCall {
dst,
iface_name,
method_name,
args,
effects,
} => ExternCall {
dst: dst.map(remap),
iface_name: iface_name.clone(),
method_name: method_name.clone(),
args: args.iter().map(|&a| remap(a)).collect(),
effects: *effects,
},
// Phase 189 FIX: Remap PHI dst and input values (BlockId remapping is done in control_flow.rs)
Phi {
dst,
inputs,
type_hint,
} => Phi {
dst: remap(*dst),
inputs: inputs.iter().map(|(bb, val)| (*bb, remap(*val))).collect(),
type_hint: type_hint.clone(),
},
// Pass through unchanged (Branch/Jump/Return handled separately)
Branch { .. } | Jump { .. } | Return { .. } | Nop | Safepoint => inst.clone(),
}
}
/// Value ID をリマップ
pub fn remap_value(&self, v: ValueId) -> ValueId {
self.value_map.get(&v).copied().unwrap_or(v)
}
/// Block ID をリマップ
#[allow(dead_code)]
pub fn remap_block(&self, func_name: &str, b: BasicBlockId) -> BasicBlockId {
self.block_map
.get(&(func_name.to_string(), b))
.copied()
.unwrap_or(b)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_remapper_new() {
let remapper = JoinIrIdRemapper::new();
assert_eq!(remapper.get_value(ValueId(0)), None);
}
#[test]
fn test_remapper_set_and_get_value() {
let mut remapper = JoinIrIdRemapper::new();
remapper.set_value(ValueId(0), ValueId(10));
assert_eq!(remapper.get_value(ValueId(0)), Some(ValueId(10)));
}
#[test]
fn test_remapper_set_and_get_block() {
let mut remapper = JoinIrIdRemapper::new();
remapper.set_block("main".to_string(), BasicBlockId(0), BasicBlockId(100));
assert_eq!(
remapper.get_block("main", BasicBlockId(0)),
Some(BasicBlockId(100))
);
}
#[test]
fn test_remap_value() {
let mut remapper = JoinIrIdRemapper::new();
remapper.set_value(ValueId(5), ValueId(50));
assert_eq!(remapper.remap_value(ValueId(5)), ValueId(50));
assert_eq!(remapper.remap_value(ValueId(99)), ValueId(99)); // Unmapped returns original
}
#[test]
fn test_collect_values_simple() {
let remapper = JoinIrIdRemapper::new();
let inst = MirInstruction::BinOp {
dst: ValueId(1),
op: crate::mir::types::BinaryOp::Add,
lhs: ValueId(2),
rhs: ValueId(3),
};
let values = remapper.collect_values_in_instruction(&inst);
assert_eq!(values, vec![ValueId(1), ValueId(2), ValueId(3)]);
}
}