166 lines
5.9 KiB
Rust
166 lines
5.9 KiB
Rust
//! 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<BasicBlockId>;
|
||
|
||
/// 命令が読む(use する)ValueId のリスト
|
||
fn reads_of(&self, inst: &MirInstruction) -> Vec<ValueId>;
|
||
|
||
/// 命令が書く(def する)ValueId のリスト
|
||
fn writes_of(&self, inst: &MirInstruction) -> Vec<ValueId>;
|
||
}
|
||
|
||
/// 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<BasicBlockId> {
|
||
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<ValueId> {
|
||
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<ValueId> = 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<ValueId> {
|
||
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(),
|
||
}
|
||
}
|
||
}
|