waffle/ir/value.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
use super::{Block, Type, Value};
use crate::pool::{ListPool, ListRef};
use crate::Operator;
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
/// A definition of an SSA value.
pub enum ValueDef {
/// This value is a block parameter of the given block, with the
/// given parameter position/index, and the given type.
BlockParam(Block, u32, Type),
/// This value is an operator, taking the given arguments, and
/// producing the given result types.
///
/// The result of an operator may be a single `Type` or a tuple of
/// types; in the latter case, valid IR must use `PickOutput` to
/// project out individual elements and use them.
Operator(Operator, ListRef<Value>, ListRef<Type>),
/// This value projects out one result of a multi-result
/// instruction: given the value, the index in the result tuple,
/// it produces a value of the given type.
PickOutput(Value, u32, Type),
/// This value is an alias of another value.
Alias(Value),
/// This value is a placeholder to be filled in later (e.g.,
/// during SSA construction, may become a blockparam or an
/// alias). Placeholders have fixed types that cannot change once
/// they are filled in.
Placeholder(Type),
/// No value: must be filled in before processing.
#[default]
None,
}
impl ValueDef {
/// Get the type of this value. Requires the type-pool. If this
/// value is an operator with zero or multiple result types, this
/// returns `None`.
pub fn ty(&self, types: &ListPool<Type>) -> Option<Type> {
match self {
&ValueDef::BlockParam(_, _, ty) => Some(ty),
&ValueDef::Operator(_, _, tys) if tys.len() == 0 => None,
&ValueDef::Operator(_, _, tys) if tys.len() == 1 => Some(types[tys][0]),
&ValueDef::PickOutput(_, _, ty) => Some(ty),
&ValueDef::Placeholder(ty) => Some(ty),
_ => None,
}
}
/// Get the tuple of types of this value.
pub fn tys<'a>(&'a self, types: &'a ListPool<Type>) -> &'a [Type] {
match self {
&ValueDef::Operator(_, _, tys) => &types[tys],
&ValueDef::BlockParam(_, _, ref ty)
| &ValueDef::PickOutput(_, _, ref ty)
| &ValueDef::Placeholder(ref ty) => std::slice::from_ref(ty),
_ => &[],
}
}
/// Visit all other values used by this value with the given
/// visitor function.
pub fn visit_uses<F: FnMut(Value)>(&self, arg_pool: &ListPool<Value>, mut f: F) {
match self {
&ValueDef::BlockParam { .. } => {}
&ValueDef::Operator(_, args, _) => {
for &arg in &arg_pool[args] {
f(arg);
}
}
&ValueDef::PickOutput(from, ..) => f(from),
&ValueDef::Alias(value) => f(value),
&ValueDef::Placeholder(_) => {}
&ValueDef::None => panic!(),
}
}
/// Visit and update all other values used by this value with the
/// given visitor function.
pub fn update_uses<F: FnMut(&mut Value)>(&mut self, arg_pool: &mut ListPool<Value>, mut f: F) {
match self {
&mut ValueDef::BlockParam { .. } => {}
&mut ValueDef::Operator(_, args, _) => {
for arg in &mut arg_pool[args] {
f(arg);
}
}
&mut ValueDef::PickOutput(ref mut from, ..) => f(from),
&mut ValueDef::Alias(ref mut value) => f(value),
&mut ValueDef::Placeholder(_) => {}
&mut ValueDef::None => panic!(),
}
}
}