naga/compact/
expressions.rs

1use super::{HandleMap, HandleSet, ModuleMap};
2use crate::arena::{Arena, Handle};
3
4pub struct ExpressionTracer<'tracer> {
5    pub constants: &'tracer Arena<crate::Constant>,
6    pub overrides: &'tracer Arena<crate::Override>,
7
8    /// The arena in which we are currently tracing expressions.
9    pub expressions: &'tracer Arena<crate::Expression>,
10
11    /// The used map for `types`.
12    pub types_used: &'tracer mut HandleSet<crate::Type>,
13
14    /// The used map for global variables.
15    pub global_variables_used: &'tracer mut HandleSet<crate::GlobalVariable>,
16
17    /// The used map for `constants`.
18    pub constants_used: &'tracer mut HandleSet<crate::Constant>,
19
20    /// The used map for `overrides`.
21    pub overrides_used: &'tracer mut HandleSet<crate::Override>,
22
23    /// The used set for `arena`.
24    ///
25    /// This points to whatever arena holds the expressions we are
26    /// currently tracing: either a function's expression arena, or
27    /// the module's constant expression arena.
28    pub expressions_used: &'tracer mut HandleSet<crate::Expression>,
29
30    /// The used set for the module's `global_expressions` arena.
31    ///
32    /// If `None`, we are already tracing the constant expressions,
33    /// and `expressions_used` already refers to their handle set.
34    pub global_expressions_used: Option<&'tracer mut HandleSet<crate::Expression>>,
35}
36
37impl ExpressionTracer<'_> {
38    /// Propagate usage through `self.expressions`, starting with `self.expressions_used`.
39    ///
40    /// Treat `self.expressions_used` as the initial set of "known
41    /// live" expressions, and follow through to identify all
42    /// transitively used expressions.
43    ///
44    /// Mark types, constants, and constant expressions used directly
45    /// by `self.expressions` as used. Items used indirectly are not
46    /// marked.
47    ///
48    /// [fe]: crate::Function::expressions
49    /// [ce]: crate::Module::global_expressions
50    pub fn trace_expressions(&mut self) {
51        log::trace!(
52            "entering trace_expression of {}",
53            if self.global_expressions_used.is_some() {
54                "function expressions"
55            } else {
56                "const expressions"
57            }
58        );
59
60        // We don't need recursion or a work list. Because an
61        // expression may only refer to other expressions that precede
62        // it in the arena, it suffices to make a single pass over the
63        // arena from back to front, marking the referents of used
64        // expressions as used themselves.
65        for (handle, expr) in self.expressions.iter().rev() {
66            // If this expression isn't used, it doesn't matter what it uses.
67            if !self.expressions_used.contains(handle) {
68                continue;
69            }
70
71            log::trace!("tracing new expression {expr:?}");
72            self.trace_expression(expr);
73        }
74    }
75
76    pub fn trace_expression(&mut self, expr: &crate::Expression) {
77        use crate::Expression as Ex;
78        match *expr {
79            // Expressions that do not contain handles that need to be traced.
80            Ex::Literal(_)
81            | Ex::FunctionArgument(_)
82            | Ex::LocalVariable(_)
83            | Ex::SubgroupBallotResult
84            | Ex::RayQueryProceedResult => {}
85
86            // Expressions can refer to constants and overrides, which can refer
87            // in turn to expressions, which complicates our nice one-pass
88            // algorithm. But since constants and overrides don't refer to each
89            // other directly, only via expressions, we can get around this by
90            // looking *through* each constant/override and marking its
91            // initializer expression as used immediately. Since `expr` refers
92            // to the constant/override, which then refers to the initializer,
93            // the initializer must precede `expr` in the arena, so we know we
94            // have yet to visit the initializer, so it's not too late to mark
95            // it.
96            Ex::Constant(handle) => {
97                self.constants_used.insert(handle);
98                let constant = &self.constants[handle];
99                self.types_used.insert(constant.ty);
100                match self.global_expressions_used {
101                    Some(ref mut used) => used.insert(constant.init),
102                    None => self.expressions_used.insert(constant.init),
103                };
104            }
105            Ex::Override(handle) => {
106                self.overrides_used.insert(handle);
107                let r#override = &self.overrides[handle];
108                self.types_used.insert(r#override.ty);
109                if let Some(init) = r#override.init {
110                    match self.global_expressions_used {
111                        Some(ref mut used) => used.insert(init),
112                        None => self.expressions_used.insert(init),
113                    };
114                }
115            }
116            Ex::ZeroValue(ty) => {
117                self.types_used.insert(ty);
118            }
119            Ex::Compose { ty, ref components } => {
120                self.types_used.insert(ty);
121                self.expressions_used
122                    .insert_iter(components.iter().cloned());
123            }
124            Ex::Access { base, index } => self.expressions_used.insert_iter([base, index]),
125            Ex::AccessIndex { base, index: _ } => {
126                self.expressions_used.insert(base);
127            }
128            Ex::Splat { size: _, value } => {
129                self.expressions_used.insert(value);
130            }
131            Ex::Swizzle {
132                size: _,
133                vector,
134                pattern: _,
135            } => {
136                self.expressions_used.insert(vector);
137            }
138            Ex::GlobalVariable(handle) => {
139                self.global_variables_used.insert(handle);
140            }
141            Ex::Load { pointer } => {
142                self.expressions_used.insert(pointer);
143            }
144            Ex::ImageSample {
145                image,
146                sampler,
147                gather: _,
148                coordinate,
149                array_index,
150                offset,
151                ref level,
152                depth_ref,
153                clamp_to_edge: _,
154            } => {
155                self.expressions_used
156                    .insert_iter([image, sampler, coordinate]);
157                self.expressions_used.insert_iter(array_index);
158                self.expressions_used.insert_iter(offset);
159                use crate::SampleLevel as Sl;
160                match *level {
161                    Sl::Auto | Sl::Zero => {}
162                    Sl::Exact(expr) | Sl::Bias(expr) => {
163                        self.expressions_used.insert(expr);
164                    }
165                    Sl::Gradient { x, y } => self.expressions_used.insert_iter([x, y]),
166                }
167                self.expressions_used.insert_iter(depth_ref);
168            }
169            Ex::ImageLoad {
170                image,
171                coordinate,
172                array_index,
173                sample,
174                level,
175            } => {
176                self.expressions_used.insert(image);
177                self.expressions_used.insert(coordinate);
178                self.expressions_used.insert_iter(array_index);
179                self.expressions_used.insert_iter(sample);
180                self.expressions_used.insert_iter(level);
181            }
182            Ex::ImageQuery { image, ref query } => {
183                self.expressions_used.insert(image);
184                use crate::ImageQuery as Iq;
185                match *query {
186                    Iq::Size { level } => self.expressions_used.insert_iter(level),
187                    Iq::NumLevels | Iq::NumLayers | Iq::NumSamples => {}
188                }
189            }
190            Ex::RayQueryVertexPositions {
191                query,
192                committed: _,
193            } => {
194                self.expressions_used.insert(query);
195            }
196            Ex::Unary { op: _, expr } => {
197                self.expressions_used.insert(expr);
198            }
199            Ex::Binary { op: _, left, right } => {
200                self.expressions_used.insert_iter([left, right]);
201            }
202            Ex::Select {
203                condition,
204                accept,
205                reject,
206            } => self
207                .expressions_used
208                .insert_iter([condition, accept, reject]),
209            Ex::Derivative {
210                axis: _,
211                ctrl: _,
212                expr,
213            } => {
214                self.expressions_used.insert(expr);
215            }
216            Ex::Relational { fun: _, argument } => {
217                self.expressions_used.insert(argument);
218            }
219            Ex::Math {
220                fun: _,
221                arg,
222                arg1,
223                arg2,
224                arg3,
225            } => {
226                self.expressions_used.insert(arg);
227                self.expressions_used.insert_iter(arg1);
228                self.expressions_used.insert_iter(arg2);
229                self.expressions_used.insert_iter(arg3);
230            }
231            Ex::As {
232                expr,
233                kind: _,
234                convert: _,
235            } => {
236                self.expressions_used.insert(expr);
237            }
238            Ex::ArrayLength(expr) => {
239                self.expressions_used.insert(expr);
240            }
241            // `CallResult` expressions do contain a function handle, but any used
242            // `CallResult` expression should have an associated `ir::Statement::Call`
243            // that we will trace.
244            Ex::CallResult(_) => {}
245            Ex::AtomicResult { ty, comparison: _ }
246            | Ex::WorkGroupUniformLoadResult { ty }
247            | Ex::SubgroupOperationResult { ty } => {
248                self.types_used.insert(ty);
249            }
250            Ex::RayQueryGetIntersection {
251                query,
252                committed: _,
253            } => {
254                self.expressions_used.insert(query);
255            }
256            Ex::CooperativeLoad { ref data, .. } => {
257                self.expressions_used.insert(data.pointer);
258                self.expressions_used.insert(data.stride);
259            }
260            Ex::CooperativeMultiplyAdd { a, b, c } => {
261                self.expressions_used.insert(a);
262                self.expressions_used.insert(b);
263                self.expressions_used.insert(c);
264            }
265        }
266    }
267}
268
269impl ModuleMap {
270    /// Fix up all handles in `expr`.
271    ///
272    /// Use the expression handle remappings in `operand_map`, and all
273    /// other mappings from `self`.
274    pub fn adjust_expression(
275        &self,
276        expr: &mut crate::Expression,
277        operand_map: &HandleMap<crate::Expression>,
278    ) {
279        let adjust = |expr: &mut Handle<crate::Expression>| {
280            operand_map.adjust(expr);
281        };
282
283        use crate::Expression as Ex;
284        match *expr {
285            // Expressions that do not contain handles that need to be adjusted.
286            Ex::Literal(_)
287            | Ex::FunctionArgument(_)
288            | Ex::LocalVariable(_)
289            | Ex::SubgroupBallotResult
290            | Ex::RayQueryProceedResult => {}
291
292            // Expressions that contain handles that need to be adjusted.
293            Ex::Constant(ref mut constant) => self.constants.adjust(constant),
294            Ex::Override(ref mut r#override) => self.overrides.adjust(r#override),
295            Ex::ZeroValue(ref mut ty) => self.types.adjust(ty),
296            Ex::Compose {
297                ref mut ty,
298                ref mut components,
299            } => {
300                self.types.adjust(ty);
301                for component in components {
302                    adjust(component);
303                }
304            }
305            Ex::Access {
306                ref mut base,
307                ref mut index,
308            } => {
309                adjust(base);
310                adjust(index);
311            }
312            Ex::AccessIndex {
313                ref mut base,
314                index: _,
315            } => adjust(base),
316            Ex::Splat {
317                size: _,
318                ref mut value,
319            } => adjust(value),
320            Ex::Swizzle {
321                size: _,
322                ref mut vector,
323                pattern: _,
324            } => adjust(vector),
325            Ex::GlobalVariable(ref mut handle) => self.globals.adjust(handle),
326            Ex::Load { ref mut pointer } => adjust(pointer),
327            Ex::ImageSample {
328                ref mut image,
329                ref mut sampler,
330                gather: _,
331                ref mut coordinate,
332                ref mut array_index,
333                ref mut offset,
334                ref mut level,
335                ref mut depth_ref,
336                clamp_to_edge: _,
337            } => {
338                adjust(image);
339                adjust(sampler);
340                adjust(coordinate);
341                operand_map.adjust_option(array_index);
342                operand_map.adjust_option(offset);
343                self.adjust_sample_level(level, operand_map);
344                operand_map.adjust_option(depth_ref);
345            }
346            Ex::ImageLoad {
347                ref mut image,
348                ref mut coordinate,
349                ref mut array_index,
350                ref mut sample,
351                ref mut level,
352            } => {
353                adjust(image);
354                adjust(coordinate);
355                operand_map.adjust_option(array_index);
356                operand_map.adjust_option(sample);
357                operand_map.adjust_option(level);
358            }
359            Ex::ImageQuery {
360                ref mut image,
361                ref mut query,
362            } => {
363                adjust(image);
364                self.adjust_image_query(query, operand_map);
365            }
366            Ex::Unary {
367                op: _,
368                ref mut expr,
369            } => adjust(expr),
370            Ex::Binary {
371                op: _,
372                ref mut left,
373                ref mut right,
374            } => {
375                adjust(left);
376                adjust(right);
377            }
378            Ex::Select {
379                ref mut condition,
380                ref mut accept,
381                ref mut reject,
382            } => {
383                adjust(condition);
384                adjust(accept);
385                adjust(reject);
386            }
387            Ex::Derivative {
388                axis: _,
389                ctrl: _,
390                ref mut expr,
391            } => adjust(expr),
392            Ex::Relational {
393                fun: _,
394                ref mut argument,
395            } => adjust(argument),
396            Ex::Math {
397                fun: _,
398                ref mut arg,
399                ref mut arg1,
400                ref mut arg2,
401                ref mut arg3,
402            } => {
403                adjust(arg);
404                operand_map.adjust_option(arg1);
405                operand_map.adjust_option(arg2);
406                operand_map.adjust_option(arg3);
407            }
408            Ex::As {
409                ref mut expr,
410                kind: _,
411                convert: _,
412            } => adjust(expr),
413            Ex::CallResult(ref mut function) => {
414                self.functions.adjust(function);
415            }
416            Ex::AtomicResult {
417                ref mut ty,
418                comparison: _,
419            } => self.types.adjust(ty),
420            Ex::WorkGroupUniformLoadResult { ref mut ty } => self.types.adjust(ty),
421            Ex::SubgroupOperationResult { ref mut ty } => self.types.adjust(ty),
422            Ex::ArrayLength(ref mut expr) => adjust(expr),
423            Ex::RayQueryGetIntersection {
424                ref mut query,
425                committed: _,
426            } => adjust(query),
427            Ex::RayQueryVertexPositions {
428                ref mut query,
429                committed: _,
430            } => adjust(query),
431            Ex::CooperativeLoad { ref mut data, .. } => {
432                adjust(&mut data.pointer);
433                adjust(&mut data.stride);
434            }
435            Ex::CooperativeMultiplyAdd {
436                ref mut a,
437                ref mut b,
438                ref mut c,
439            } => {
440                adjust(a);
441                adjust(b);
442                adjust(c);
443            }
444        }
445    }
446
447    fn adjust_sample_level(
448        &self,
449        level: &mut crate::SampleLevel,
450        operand_map: &HandleMap<crate::Expression>,
451    ) {
452        let adjust = |expr: &mut Handle<crate::Expression>| operand_map.adjust(expr);
453
454        use crate::SampleLevel as Sl;
455        match *level {
456            Sl::Auto | Sl::Zero => {}
457            Sl::Exact(ref mut expr) => adjust(expr),
458            Sl::Bias(ref mut expr) => adjust(expr),
459            Sl::Gradient {
460                ref mut x,
461                ref mut y,
462            } => {
463                adjust(x);
464                adjust(y);
465            }
466        }
467    }
468
469    fn adjust_image_query(
470        &self,
471        query: &mut crate::ImageQuery,
472        operand_map: &HandleMap<crate::Expression>,
473    ) {
474        use crate::ImageQuery as Iq;
475
476        match *query {
477            Iq::Size { ref mut level } => operand_map.adjust_option(level),
478            Iq::NumLevels | Iq::NumLayers | Iq::NumSamples => {}
479        }
480    }
481}