Phase 63-6-1: MirInstruction::Phi に type_hint フィールド追加 - Added `type_hint: Option<MirType>` field to Phi instruction - Updated 21 files with type_hint initialization (all set to None for legacy paths) - Pattern matching updated across codebase (11 files) - Test code updated (basic_block.rs) Phase 63-6-2: JoinIR→MIR Bridge で型ヒント伝播実装 - Modified convert.rs: Select → MIR now creates PHI with type_hint - Removed Copy instructions from then/else blocks - PHI instruction at merge block receives type_hint from JoinIR Select - Test verification: ✅ Type hint propagation successful (Some(Integer)) Modified files: - instruction.rs: Added type_hint field definition - join_ir_vm_bridge/convert.rs: Select lowering with PHI + type_hint - 19 other files: type_hint field initialization Test results: - ✅ test_type_hint_propagation_simple: Type hint = Some(Integer) confirmed - ✅ 7/8 if_select tests passing (1 race condition, passes individually) Next: Phase 63-6-3 (lifecycle.rs で型ヒント使用) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
804 lines
25 KiB
Rust
804 lines
25 KiB
Rust
//! Kind-specific instruction metadata (PoC) used to gradually
|
|
//! move large enum matches to small, testable structs.
|
|
//!
|
|
//! Non-functional: only mirrors data for selected instructions and
|
|
//! provides introspection (effects/dst/used). Core behavior remains
|
|
//! in `MirInstruction`.
|
|
|
|
use super::{BasicBlockId, ConstValue, Effect, EffectMask, ValueId};
|
|
use crate::mir::instruction::MirInstruction;
|
|
use crate::mir::types::{
|
|
BarrierOp as MirBarrierOp, BinaryOp as MirBinOp, MirType, TypeOpKind as MirTypeOpKind,
|
|
WeakRefOp as MirWeakRefOp,
|
|
};
|
|
|
|
// Local macro utilities for generating InstructionMeta boilerplate.
|
|
// This macro is intentionally scoped to this module to avoid polluting the crate namespace.
|
|
macro_rules! inst_meta {
|
|
(
|
|
$(
|
|
pub struct $name:ident { $($field:ident : $fty:ty),* $(,)? }
|
|
=> {
|
|
from_mir = |$i:ident| $from_expr:expr;
|
|
effects = $effects:expr;
|
|
dst = $dst:expr;
|
|
used = $used:expr;
|
|
}
|
|
)+
|
|
) => {
|
|
$(
|
|
#[derive(Debug, Clone)]
|
|
pub struct $name { $(pub $field: $fty),* }
|
|
|
|
impl $name {
|
|
pub fn from_mir($i: &MirInstruction) -> Option<Self> { $from_expr }
|
|
}
|
|
|
|
impl InstructionMeta for $name {
|
|
fn effects(&self) -> EffectMask { ($effects)(self) }
|
|
fn dst(&self) -> Option<ValueId> { ($dst)(self) }
|
|
fn used(&self) -> Vec<ValueId> { ($used)(self) }
|
|
}
|
|
)+
|
|
};
|
|
}
|
|
|
|
pub trait InstructionMeta {
|
|
fn effects(&self) -> EffectMask;
|
|
fn dst(&self) -> Option<ValueId>;
|
|
fn used(&self) -> Vec<ValueId>;
|
|
}
|
|
|
|
// ---- Const ----
|
|
#[derive(Debug, Clone)]
|
|
pub struct ConstInst {
|
|
pub dst: ValueId,
|
|
pub value: ConstValue,
|
|
}
|
|
|
|
impl ConstInst {
|
|
pub fn from_mir(i: &MirInstruction) -> Option<Self> {
|
|
match i {
|
|
MirInstruction::Const { dst, value } => Some(ConstInst {
|
|
dst: *dst,
|
|
value: value.clone(),
|
|
}),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl InstructionMeta for ConstInst {
|
|
fn effects(&self) -> EffectMask {
|
|
EffectMask::PURE
|
|
}
|
|
fn dst(&self) -> Option<ValueId> {
|
|
Some(self.dst)
|
|
}
|
|
fn used(&self) -> Vec<ValueId> {
|
|
Vec::new()
|
|
}
|
|
}
|
|
|
|
// ---- BinOp ----
|
|
#[derive(Debug, Clone)]
|
|
pub struct BinOpInst {
|
|
pub dst: ValueId,
|
|
pub op: MirBinOp,
|
|
pub lhs: ValueId,
|
|
pub rhs: ValueId,
|
|
}
|
|
|
|
impl BinOpInst {
|
|
pub fn from_mir(i: &MirInstruction) -> Option<Self> {
|
|
match i {
|
|
MirInstruction::BinOp { dst, op, lhs, rhs } => Some(BinOpInst {
|
|
dst: *dst,
|
|
op: *op,
|
|
lhs: *lhs,
|
|
rhs: *rhs,
|
|
}),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl InstructionMeta for BinOpInst {
|
|
fn effects(&self) -> EffectMask {
|
|
EffectMask::PURE
|
|
}
|
|
fn dst(&self) -> Option<ValueId> {
|
|
Some(self.dst)
|
|
}
|
|
fn used(&self) -> Vec<ValueId> {
|
|
vec![self.lhs, self.rhs]
|
|
}
|
|
}
|
|
|
|
// ---- Helper delegation for MirInstruction methods ----
|
|
|
|
pub fn effects_via_meta(i: &MirInstruction) -> Option<EffectMask> {
|
|
if let Some(k) = ConstInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = BinOpInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = UnaryOpInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = CompareInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = LoadInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = CastInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = TypeOpInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = ArrayGetInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = PhiInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = NewBoxInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = StoreInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = ArraySetInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = ReturnInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = BranchInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = JumpInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = PrintInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = DebugInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = TypeCheckInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = CopyInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = NopInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = ThrowInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = CatchInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = SafepointInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
if let Some(k) = NewClosureInst::from_mir(i) {
|
|
return Some(k.effects());
|
|
}
|
|
None
|
|
}
|
|
|
|
pub fn dst_via_meta(i: &MirInstruction) -> Option<ValueId> {
|
|
if let Some(k) = ConstInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = BinOpInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = UnaryOpInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = CompareInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = LoadInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = CastInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = TypeOpInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = ArrayGetInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = PhiInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = NewBoxInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(_k) = StoreInst::from_mir(i) {
|
|
return None;
|
|
}
|
|
if let Some(_k) = ArraySetInst::from_mir(i) {
|
|
return None;
|
|
}
|
|
if let Some(_k) = ReturnInst::from_mir(i) {
|
|
return None;
|
|
}
|
|
if let Some(_k) = BranchInst::from_mir(i) {
|
|
return None;
|
|
}
|
|
if let Some(_k) = JumpInst::from_mir(i) {
|
|
return None;
|
|
}
|
|
if let Some(_k) = PrintInst::from_mir(i) {
|
|
return None;
|
|
}
|
|
if let Some(_k) = DebugInst::from_mir(i) {
|
|
return None;
|
|
}
|
|
if let Some(k) = CallLikeInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = TypeCheckInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(k) = CopyInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(_k) = NopInst::from_mir(i) {
|
|
return None;
|
|
}
|
|
if let Some(_k) = ThrowInst::from_mir(i) {
|
|
return None;
|
|
}
|
|
if let Some(k) = CatchInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
if let Some(_k) = SafepointInst::from_mir(i) {
|
|
return None;
|
|
}
|
|
if let Some(k) = NewClosureInst::from_mir(i) {
|
|
return k.dst();
|
|
}
|
|
None
|
|
}
|
|
|
|
pub fn used_via_meta(i: &MirInstruction) -> Option<Vec<ValueId>> {
|
|
if let Some(k) = ConstInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = BinOpInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = UnaryOpInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = CompareInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = LoadInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = CastInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = TypeOpInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = ArrayGetInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = PhiInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = NewBoxInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = StoreInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = ArraySetInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = ReturnInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = BranchInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = JumpInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = PrintInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = DebugInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = CallLikeInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = TypeCheckInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = CopyInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = NopInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = ThrowInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = CatchInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = SafepointInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
if let Some(k) = NewClosureInst::from_mir(i) {
|
|
return Some(k.used());
|
|
}
|
|
None
|
|
}
|
|
|
|
// ---- BarrierRead ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct BarrierReadInst { ptr: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::BarrierRead { ptr } => Some(BarrierReadInst { ptr: *ptr }), _ => None };
|
|
effects = |_: &Self| EffectMask::READ.add(Effect::Barrier);
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.ptr];
|
|
}
|
|
}
|
|
|
|
// ---- BarrierWrite ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct BarrierWriteInst { ptr: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::BarrierWrite { ptr } => Some(BarrierWriteInst { ptr: *ptr }), _ => None };
|
|
effects = |_: &Self| EffectMask::WRITE.add(Effect::Barrier);
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.ptr];
|
|
}
|
|
}
|
|
|
|
// ---- Barrier (unified) ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct BarrierInst { op: MirBarrierOp, ptr: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Barrier { op, ptr } => Some(BarrierInst { op: *op, ptr: *ptr }), _ => None };
|
|
effects = |s: &Self| match s.op { MirBarrierOp::Read => EffectMask::READ.add(Effect::Barrier), MirBarrierOp::Write => EffectMask::WRITE.add(Effect::Barrier) };
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.ptr];
|
|
}
|
|
}
|
|
|
|
// ---- Ref ops ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct RefNewInst { dst: ValueId, box_val: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::RefNew { dst, box_val } => Some(RefNewInst { dst: *dst, box_val: *box_val }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.box_val];
|
|
}
|
|
}
|
|
inst_meta! {
|
|
pub struct RefGetInst { dst: ValueId, reference: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::RefGet { dst, reference, .. } => Some(RefGetInst { dst: *dst, reference: *reference }), _ => None };
|
|
effects = |_: &Self| EffectMask::READ;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.reference];
|
|
}
|
|
}
|
|
inst_meta! {
|
|
pub struct RefSetInst { reference: ValueId, value: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::RefSet { reference, value, .. } => Some(RefSetInst { reference: *reference, value: *value }), _ => None };
|
|
effects = |_: &Self| EffectMask::WRITE;
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.reference, s.value];
|
|
}
|
|
}
|
|
|
|
// ---- Weak ops ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct WeakNewInst { dst: ValueId, box_val: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::WeakNew { dst, box_val } => Some(WeakNewInst { dst: *dst, box_val: *box_val }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.box_val];
|
|
}
|
|
}
|
|
inst_meta! {
|
|
pub struct WeakLoadInst { dst: ValueId, weak_ref: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::WeakLoad { dst, weak_ref } => Some(WeakLoadInst { dst: *dst, weak_ref: *weak_ref }), _ => None };
|
|
effects = |_: &Self| EffectMask::READ;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.weak_ref];
|
|
}
|
|
}
|
|
inst_meta! {
|
|
pub struct WeakRefInst { dst: ValueId, op: MirWeakRefOp, value: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::WeakRef { dst, op, value } => Some(WeakRefInst { dst: *dst, op: *op, value: *value }), _ => None };
|
|
effects = |s: &Self| match s.op { MirWeakRefOp::New => EffectMask::PURE, MirWeakRefOp::Load => EffectMask::READ };
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.value];
|
|
}
|
|
}
|
|
|
|
// ---- Future ops ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct FutureNewInst { dst: ValueId, value: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::FutureNew { dst, value } => Some(FutureNewInst { dst: *dst, value: *value }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE.add(Effect::Alloc);
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.value];
|
|
}
|
|
}
|
|
inst_meta! {
|
|
pub struct FutureSetInst { future: ValueId, value: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::FutureSet { future, value } => Some(FutureSetInst { future: *future, value: *value }), _ => None };
|
|
effects = |_: &Self| EffectMask::WRITE;
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.future, s.value];
|
|
}
|
|
}
|
|
inst_meta! {
|
|
pub struct AwaitInst { dst: ValueId, future: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Await { dst, future } => Some(AwaitInst { dst: *dst, future: *future }), _ => None };
|
|
effects = |_: &Self| EffectMask::READ.add(Effect::Async);
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.future];
|
|
}
|
|
}
|
|
|
|
// ---- UnaryOp ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct UnaryOpInst { dst: ValueId, operand: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::UnaryOp { dst, operand, .. } => Some(UnaryOpInst { dst: *dst, operand: *operand }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.operand];
|
|
}
|
|
}
|
|
|
|
// ---- Compare ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct CompareInst { dst: ValueId, lhs: ValueId, rhs: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Compare { dst, lhs, rhs, .. } => Some(CompareInst { dst: *dst, lhs: *lhs, rhs: *rhs }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.lhs, s.rhs];
|
|
}
|
|
}
|
|
|
|
// ---- Load ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct LoadInst { dst: ValueId, ptr: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Load { dst, ptr } => Some(LoadInst { dst: *dst, ptr: *ptr }), _ => None };
|
|
effects = |_: &Self| EffectMask::READ;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.ptr];
|
|
}
|
|
}
|
|
|
|
// ---- Cast ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct CastInst { dst: ValueId, value: ValueId, target_type: MirType }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Cast { dst, value, target_type } => Some(CastInst { dst: *dst, value: *value, target_type: target_type.clone() }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.value];
|
|
}
|
|
}
|
|
|
|
// ---- TypeOp ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct TypeOpInst { dst: ValueId, op: MirTypeOpKind, value: ValueId, ty: MirType }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::TypeOp { dst, op, value, ty } => Some(TypeOpInst { dst: *dst, op: *op, value: *value, ty: ty.clone() }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.value];
|
|
}
|
|
}
|
|
|
|
// ---- ArrayGet ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct ArrayGetInst { dst: ValueId, array: ValueId, index: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::ArrayGet { dst, array, index } => Some(ArrayGetInst { dst: *dst, array: *array, index: *index }), _ => None };
|
|
effects = |_: &Self| EffectMask::READ;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.array, s.index];
|
|
}
|
|
}
|
|
|
|
// ---- Phi ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct PhiInst { dst: ValueId, inputs: Vec<(BasicBlockId, ValueId)> }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Phi { dst, inputs, .. } => Some(PhiInst { dst: *dst, inputs: inputs.clone() }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| s.inputs.iter().map(|(_, v)| *v).collect();
|
|
}
|
|
}
|
|
|
|
// ---- NewBox ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct NewBoxInst { dst: ValueId, args: Vec<ValueId> }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::NewBox { dst, args, .. } => Some(NewBoxInst { dst: *dst, args: args.clone() }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE.add(Effect::Alloc);
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| s.args.clone();
|
|
}
|
|
}
|
|
|
|
// ---- NewClosure ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct NewClosureInst { dst: ValueId, captures: Vec<(String, ValueId)>, me: Option<ValueId> }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::NewClosure { dst, captures, me, .. } => Some(NewClosureInst { dst: *dst, captures: captures.clone(), me: *me }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE.add(Effect::Alloc);
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| { let mut v: Vec<ValueId> = s.captures.iter().map(|(_, id)| *id).collect(); if let Some(m) = s.me { v.push(m); } v };
|
|
}
|
|
}
|
|
|
|
// ---- Store ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct StoreInst { value: ValueId, ptr: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Store { value, ptr } => Some(StoreInst { value: *value, ptr: *ptr }), _ => None };
|
|
effects = |_: &Self| EffectMask::WRITE;
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.value, s.ptr];
|
|
}
|
|
}
|
|
|
|
// ---- ArraySet ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct ArraySetInst { array: ValueId, index: ValueId, value: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::ArraySet { array, index, value } => Some(ArraySetInst { array: *array, index: *index, value: *value }), _ => None };
|
|
effects = |_: &Self| EffectMask::WRITE;
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.array, s.index, s.value];
|
|
}
|
|
}
|
|
|
|
// ---- Return ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct ReturnInst { value: Option<ValueId> }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Return { value } => Some(ReturnInst { value: *value }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| s.value.map(|v| vec![v]).unwrap_or_default();
|
|
}
|
|
}
|
|
|
|
// ---- Branch ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct BranchInst { condition: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Branch { condition, .. } => Some(BranchInst { condition: *condition }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.condition];
|
|
}
|
|
}
|
|
|
|
// ---- Jump ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct JumpInst { }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Jump { .. } => Some(JumpInst {}), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |_: &Self| None;
|
|
used = |_: &Self| Vec::new();
|
|
}
|
|
}
|
|
|
|
// ---- Print ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct PrintInst { value: ValueId, effects_mask: EffectMask }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Print { value, effects } => Some(PrintInst { value: *value, effects_mask: *effects }), _ => None };
|
|
effects = |s: &Self| s.effects_mask;
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.value];
|
|
}
|
|
}
|
|
|
|
// ---- Debug ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct DebugInst { value: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Debug { value, .. } => Some(DebugInst { value: *value }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE.add(Effect::Debug);
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.value];
|
|
}
|
|
}
|
|
|
|
// ---- TypeCheck ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct TypeCheckInst { dst: ValueId, value: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::TypeCheck { dst, value, .. } => Some(TypeCheckInst { dst: *dst, value: *value }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.value];
|
|
}
|
|
}
|
|
|
|
// ---- Copy ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct CopyInst { dst: ValueId, src: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Copy { dst, src } => Some(CopyInst { dst: *dst, src: *src }), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |s: &Self| Some(s.dst);
|
|
used = |s: &Self| vec![s.src];
|
|
}
|
|
}
|
|
|
|
// ---- Nop ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct NopInst { }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Nop => Some(NopInst {}), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |_: &Self| None;
|
|
used = |_: &Self| Vec::new();
|
|
}
|
|
}
|
|
|
|
// ---- Throw ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct ThrowInst { exception: ValueId, effects_mask: EffectMask }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Throw { exception, effects } => Some(ThrowInst { exception: *exception, effects_mask: *effects }), _ => None };
|
|
effects = |s: &Self| s.effects_mask;
|
|
dst = |_: &Self| None;
|
|
used = |s: &Self| vec![s.exception];
|
|
}
|
|
}
|
|
|
|
// ---- Catch ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct CatchInst { exception_value: ValueId }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Catch { exception_value, .. } => Some(CatchInst { exception_value: *exception_value }), _ => None };
|
|
effects = |_: &Self| EffectMask::CONTROL;
|
|
dst = |s: &Self| Some(s.exception_value);
|
|
used = |_: &Self| Vec::new();
|
|
}
|
|
}
|
|
|
|
// ---- Safepoint ---- (macro-generated)
|
|
inst_meta! {
|
|
pub struct SafepointInst { }
|
|
=> {
|
|
from_mir = |i| match i { MirInstruction::Safepoint => Some(SafepointInst {}), _ => None };
|
|
effects = |_: &Self| EffectMask::PURE;
|
|
dst = |_: &Self| None;
|
|
used = |_: &Self| Vec::new();
|
|
}
|
|
}
|
|
|
|
// ---- Call-like (dst/used only; effects fallback in MirInstruction) ----
|
|
#[derive(Debug, Clone)]
|
|
pub enum CallLikeInst {
|
|
Call {
|
|
dst: Option<ValueId>,
|
|
func: ValueId,
|
|
args: Vec<ValueId>,
|
|
},
|
|
BoxCall {
|
|
dst: Option<ValueId>,
|
|
box_val: ValueId,
|
|
args: Vec<ValueId>,
|
|
},
|
|
PluginInvoke {
|
|
dst: Option<ValueId>,
|
|
box_val: ValueId,
|
|
args: Vec<ValueId>,
|
|
},
|
|
ExternCall {
|
|
dst: Option<ValueId>,
|
|
args: Vec<ValueId>,
|
|
},
|
|
}
|
|
|
|
impl CallLikeInst {
|
|
pub fn from_mir(i: &MirInstruction) -> Option<Self> {
|
|
match i {
|
|
MirInstruction::Call {
|
|
dst, func, args, ..
|
|
} => Some(CallLikeInst::Call {
|
|
dst: *dst,
|
|
func: *func,
|
|
args: args.clone(),
|
|
}),
|
|
MirInstruction::BoxCall {
|
|
dst, box_val, args, ..
|
|
} => Some(CallLikeInst::BoxCall {
|
|
dst: *dst,
|
|
box_val: *box_val,
|
|
args: args.clone(),
|
|
}),
|
|
MirInstruction::PluginInvoke {
|
|
dst, box_val, args, ..
|
|
} => Some(CallLikeInst::PluginInvoke {
|
|
dst: *dst,
|
|
box_val: *box_val,
|
|
args: args.clone(),
|
|
}),
|
|
MirInstruction::ExternCall { dst, args, .. } => Some(CallLikeInst::ExternCall {
|
|
dst: *dst,
|
|
args: args.clone(),
|
|
}),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn dst(&self) -> Option<ValueId> {
|
|
match self {
|
|
CallLikeInst::Call { dst, .. }
|
|
| CallLikeInst::BoxCall { dst, .. }
|
|
| CallLikeInst::PluginInvoke { dst, .. }
|
|
| CallLikeInst::ExternCall { dst, .. } => *dst,
|
|
}
|
|
}
|
|
|
|
pub fn used(&self) -> Vec<ValueId> {
|
|
match self {
|
|
CallLikeInst::Call { func, args, .. } => {
|
|
let mut v = Vec::new();
|
|
// func は legacy 経路では「関数値」を指すが、unified 経路では
|
|
// ValueId::INVALID がダミーとして入る。INVALID の場合は SSA の
|
|
// 使用値としては数えず、args のみを使用値とみなす。
|
|
if *func != ValueId::INVALID {
|
|
v.push(*func);
|
|
}
|
|
v.extend(args.iter().copied());
|
|
v
|
|
}
|
|
CallLikeInst::BoxCall { box_val, args, .. }
|
|
| CallLikeInst::PluginInvoke { box_val, args, .. } => {
|
|
let mut v = vec![*box_val];
|
|
v.extend(args.iter().copied());
|
|
v
|
|
}
|
|
CallLikeInst::ExternCall { args, .. } => args.clone(),
|
|
}
|
|
}
|
|
}
|