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!(),
        }
    }
}