483 lines
16 KiB
Rust
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)]);
|
|
}
|
|
}
|