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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use crate::arena::{Arena, Handle};

struct Interface<'a> {
    expressions: &'a Arena<crate::Expression>,
    uses: Vec<crate::GlobalUse>,
}

impl<'a> Interface<'a> {
    fn add_inputs(&mut self, handle: Handle<crate::Expression>) {
        use crate::Expression as E;
        match self.expressions[handle] {
            E::Access { base, index } => {
                self.add_inputs(base);
                self.add_inputs(index);
            }
            E::AccessIndex { base, .. } => {
                self.add_inputs(base);
            }
            E::Constant(_) => {}
            E::Compose { ref components, .. } => {
                for &comp in components {
                    self.add_inputs(comp);
                }
            }
            E::FunctionParameter(_) => {}
            E::GlobalVariable(handle) => {
                self.uses[handle.index()] |= crate::GlobalUse::LOAD;
            }
            E::LocalVariable(_) => {}
            E::Load { pointer } => {
                self.add_inputs(pointer);
            }
            E::ImageSample {
                image,
                sampler,
                coordinate,
            } => {
                self.add_inputs(image);
                self.add_inputs(sampler);
                self.add_inputs(coordinate);
            }
            E::Unary { expr, .. } => {
                self.add_inputs(expr);
            }
            E::Binary { left, right, .. } => {
                self.add_inputs(left);
                self.add_inputs(right);
            }
            E::Intrinsic { argument, .. } => {
                self.add_inputs(argument);
            }
            E::DotProduct(left, right) => {
                self.add_inputs(left);
                self.add_inputs(right);
            }
            E::CrossProduct(left, right) => {
                self.add_inputs(left);
                self.add_inputs(right);
            }
            E::Derivative { expr, .. } => {
                self.add_inputs(expr);
            }
            E::Call { ref arguments, .. } => {
                for &argument in arguments {
                    self.add_inputs(argument);
                }
            }
        }
    }

    fn collect(&mut self, block: &[crate::Statement]) {
        for statement in block {
            use crate::Statement as S;
            match *statement {
                S::Empty | S::Break | S::Continue | S::Kill => (),
                S::Block(ref b) => {
                    self.collect(b);
                }
                S::If {
                    condition,
                    ref accept,
                    ref reject,
                } => {
                    self.add_inputs(condition);
                    self.collect(accept);
                    self.collect(reject);
                }
                S::Switch {
                    selector,
                    ref cases,
                    ref default,
                } => {
                    self.add_inputs(selector);
                    for &(ref case, _) in cases.values() {
                        self.collect(case);
                    }
                    self.collect(default);
                }
                S::Loop {
                    ref body,
                    ref continuing,
                } => {
                    self.collect(body);
                    self.collect(continuing);
                }
                S::Return { value } => {
                    if let Some(expr) = value {
                        self.add_inputs(expr);
                    }
                }
                S::Store { pointer, value } => {
                    let mut left = pointer;
                    loop {
                        match self.expressions[left] {
                            crate::Expression::Access { base, index } => {
                                self.add_inputs(index);
                                left = base;
                            }
                            crate::Expression::AccessIndex { base, .. } => {
                                left = base;
                            }
                            crate::Expression::GlobalVariable(handle) => {
                                self.uses[handle.index()] |= crate::GlobalUse::STORE;
                                break;
                            }
                            _ => break,
                        }
                    }
                    self.add_inputs(value);
                }
            }
        }
    }
}

impl crate::GlobalUse {
    pub fn scan(
        expressions: &Arena<crate::Expression>,
        body: &[crate::Statement],
        globals: &Arena<crate::GlobalVariable>,
    ) -> Vec<Self> {
        let mut io = Interface {
            expressions,
            uses: vec![crate::GlobalUse::empty(); globals.len()],
        };
        io.collect(body);
        io.uses
    }
}