//! MirQuery - Read/Write/CFGビューを提供する共通窓口 //! //! Box理論: MIR 全体の構造は MirQueryBox が保持し、他の箱(ExitLiveness など)は //! 「見せる窓」である MirQuery トレイト越しにしか触らないようにする。 //! これにより MIR 構造への依存を最小化し、テスタビリティと疎結合を保つ。 use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; /// MIR への読み取り専用ビュー pub trait MirQuery { /// ブロック内の命令列(PHI を含む)を順序付きで返す fn insts_in_block(&self, bb: BasicBlockId) -> &[MirInstruction]; /// ブロックの後続(succs)を決定的順序で返す fn succs(&self, bb: BasicBlockId) -> Vec; /// 命令が読む(use する)ValueId のリスト fn reads_of(&self, inst: &MirInstruction) -> Vec; /// 命令が書く(def する)ValueId のリスト fn writes_of(&self, inst: &MirInstruction) -> Vec; } /// MirQuery の標準実装:MirFunction 全体を抱えつつビューを提供 pub struct MirQueryBox<'m> { mir: &'m MirFunction, } impl<'m> MirQueryBox<'m> { pub fn new(mir: &'m MirFunction) -> Self { Self { mir } } } impl<'m> MirQuery for MirQueryBox<'m> { fn insts_in_block(&self, bb: BasicBlockId) -> &[MirInstruction] { static EMPTY: &[MirInstruction] = &[]; self.mir .blocks .get(&bb) .map(|bb| bb.instructions.as_slice()) .unwrap_or(EMPTY) } fn succs(&self, bb: BasicBlockId) -> Vec { let mut v: Vec<_> = self .mir .blocks .get(&bb) .map(|bb| bb.successors.iter().copied().collect()) .unwrap_or_else(Vec::new); v.sort_by_key(|b| b.0); v } fn reads_of(&self, inst: &MirInstruction) -> Vec { use MirInstruction::*; match inst { Const { .. } | Nop => Vec::new(), Copy { src, .. } => vec![*src], UnaryOp { operand, .. } => vec![*operand], BinOp { lhs, rhs, .. } | Compare { lhs, rhs, .. } => { vec![*lhs, *rhs] } TypeOp { value, .. } | TypeCheck { value, .. } | Cast { value, .. } => { vec![*value] } Load { ptr, .. } => vec![*ptr], Store { ptr, value } => vec![*ptr, *value], ArrayGet { array, index, .. } => vec![*array, *index], ArraySet { array, index, value, .. } => vec![*array, *index, *value], Call { args, .. } | BoxCall { args, .. } | PluginInvoke { args, .. } | ExternCall { args, .. } => args.clone(), Return { value } => value.iter().copied().collect(), Branch { condition, .. } => vec![*condition], Jump { .. } => Vec::new(), Phi { inputs, .. } => inputs.iter().map(|(_, v)| *v).collect(), NewBox { args, .. } => args.clone(), Debug { value, .. } | Print { value, .. } => vec![*value], DebugLog { values, .. } => values.clone(), Throw { exception, .. } => vec![*exception], Catch { .. } => Vec::new(), NewClosure { captures, me, .. } => { let mut v: Vec = captures.iter().map(|(_, v)| *v).collect(); if let Some(m) = me { v.push(*m); } v } RefNew { box_val, .. } => vec![*box_val], RefGet { reference, .. } => vec![*reference], RefSet { reference, value, .. } => vec![*reference, *value], WeakNew { box_val, .. } => vec![*box_val], WeakLoad { weak_ref, .. } => vec![*weak_ref], WeakRef { value, .. } => vec![*value], BarrierRead { ptr } | BarrierWrite { ptr } | Barrier { ptr, .. } => { vec![*ptr] } FutureNew { value, .. } => vec![*value], FutureSet { future, value } => vec![*future, *value], Await { future, .. } => vec![*future], Safepoint => Vec::new(), } } fn writes_of(&self, inst: &MirInstruction) -> Vec { use MirInstruction::*; match inst { Const { dst, .. } | UnaryOp { dst, .. } | BinOp { dst, .. } | Compare { dst, .. } | TypeOp { dst, .. } | Cast { dst, .. } | Load { dst, .. } | ArrayGet { dst, .. } | Call { dst: Some(dst), .. } | BoxCall { dst: Some(dst), .. } | PluginInvoke { dst: Some(dst), .. } | ExternCall { dst: Some(dst), .. } | Phi { dst, .. } | NewBox { dst, .. } | RefNew { dst, .. } | RefGet { dst, .. } | WeakNew { dst, .. } | WeakLoad { dst, .. } | WeakRef { dst, .. } | FutureNew { dst, .. } | NewClosure { dst, .. } | Await { dst, .. } | Copy { dst, .. } => vec![*dst], // Copy writes to dst // No writes Nop | Store { .. } | ArraySet { .. } | Call { dst: None, .. } | BoxCall { dst: None, .. } | PluginInvoke { dst: None, .. } | ExternCall { dst: None, .. } | Return { .. } | Branch { .. } | Jump { .. } | Debug { .. } | DebugLog { .. } | Print { .. } | Throw { .. } | Catch { .. } | BarrierRead { .. } | BarrierWrite { .. } | Barrier { .. } | FutureSet { .. } | Safepoint => Vec::new(), _ => Vec::new(), } } }