Skip to main content

naga/compact/
statements.rs

1use alloc::{vec, vec::Vec};
2
3use super::functions::FunctionTracer;
4use super::FunctionMap;
5use crate::arena::Handle;
6use crate::compact::handle_set_map::HandleMap;
7
8impl FunctionTracer<'_> {
9    pub fn trace_block(&mut self, block: &[crate::Statement]) {
10        self.trace_block_impl(block, false)
11    }
12
13    /// Like [`Self::trace_block`], but also mark every [`Emit`]ted expression
14    /// as used, whether or not anything needs its value.
15    ///
16    /// Compaction only keeps values something actually needs, so
17    /// `trace_block` ignores `Emit` statements. A consumer that has to account
18    /// for every expression the generated code *mentions*, rather than every
19    /// expression it needs, wants this instead: the MSL backend does no dead
20    /// code elimination, so it writes out a definition for each expression it
21    /// bakes whether or not anything reads it, and that definition refers to
22    /// the expression's operands.
23    ///
24    /// [`Emit`]: crate::Statement::Emit
25    #[cfg(msl_out)]
26    pub fn trace_block_including_emits(&mut self, block: &[crate::Statement]) {
27        self.trace_block_impl(block, true)
28    }
29
30    fn trace_block_impl(&mut self, block: &[crate::Statement], emits_are_used: bool) {
31        let mut worklist: Vec<&[crate::Statement]> = vec![block];
32        while let Some(last) = worklist.pop() {
33            for stmt in last {
34                use crate::Statement as St;
35                match *stmt {
36                    St::Emit(ref range) => {
37                        // If we come across a statement that actually uses an
38                        // expression in this range, it'll get traced from
39                        // there. But since evaluating expressions has no
40                        // effect, we don't need to assume that everything
41                        // emitted is live - unless our caller says otherwise.
42                        if emits_are_used {
43                            self.expressions_used.insert_iter(range.clone());
44                        }
45                    }
46                    St::Block(ref block) => worklist.push(block),
47                    St::If {
48                        condition,
49                        ref accept,
50                        ref reject,
51                    } => {
52                        self.expressions_used.insert(condition);
53                        worklist.push(accept);
54                        worklist.push(reject);
55                    }
56                    St::Switch {
57                        selector,
58                        ref cases,
59                    } => {
60                        self.expressions_used.insert(selector);
61                        for case in cases {
62                            worklist.push(&case.body);
63                        }
64                    }
65                    St::Loop {
66                        ref body,
67                        ref continuing,
68                        break_if,
69                    } => {
70                        if let Some(break_if) = break_if {
71                            self.expressions_used.insert(break_if);
72                        }
73                        worklist.push(body);
74                        worklist.push(continuing);
75                    }
76                    St::Return { value: Some(value) } => {
77                        self.expressions_used.insert(value);
78                    }
79                    St::Store { pointer, value } => {
80                        self.expressions_used.insert(pointer);
81                        self.expressions_used.insert(value);
82                    }
83                    St::ImageStore {
84                        image,
85                        coordinate,
86                        array_index,
87                        value,
88                    } => {
89                        self.expressions_used.insert(image);
90                        self.expressions_used.insert(coordinate);
91                        if let Some(array_index) = array_index {
92                            self.expressions_used.insert(array_index);
93                        }
94                        self.expressions_used.insert(value);
95                    }
96                    St::Atomic {
97                        pointer,
98                        ref fun,
99                        value,
100                        result,
101                    } => {
102                        self.expressions_used.insert(pointer);
103                        self.trace_atomic_function(fun);
104                        self.expressions_used.insert(value);
105                        if let Some(result) = result {
106                            self.expressions_used.insert(result);
107                        }
108                    }
109                    St::ImageAtomic {
110                        image,
111                        coordinate,
112                        array_index,
113                        fun: _,
114                        value,
115                    } => {
116                        self.expressions_used.insert(image);
117                        self.expressions_used.insert(coordinate);
118                        if let Some(array_index) = array_index {
119                            self.expressions_used.insert(array_index);
120                        }
121                        self.expressions_used.insert(value);
122                    }
123                    St::WorkGroupUniformLoad { pointer, result } => {
124                        self.expressions_used.insert(pointer);
125                        self.expressions_used.insert(result);
126                    }
127                    St::Call {
128                        function,
129                        ref arguments,
130                        result,
131                    } => {
132                        self.trace_call(function);
133                        for expr in arguments {
134                            self.expressions_used.insert(*expr);
135                        }
136                        if let Some(result) = result {
137                            self.expressions_used.insert(result);
138                        }
139                    }
140                    St::RayQuery { query, ref fun } => {
141                        self.expressions_used.insert(query);
142                        self.trace_ray_query_function(fun);
143                    }
144                    St::SubgroupBallot { result, predicate } => {
145                        if let Some(predicate) = predicate {
146                            self.expressions_used.insert(predicate);
147                        }
148                        self.expressions_used.insert(result);
149                    }
150                    St::SubgroupCollectiveOperation {
151                        op: _,
152                        collective_op: _,
153                        argument,
154                        result,
155                    } => {
156                        self.expressions_used.insert(argument);
157                        self.expressions_used.insert(result);
158                    }
159                    St::SubgroupGather {
160                        mode,
161                        argument,
162                        result,
163                    } => {
164                        match mode {
165                            crate::GatherMode::BroadcastFirst => {}
166                            crate::GatherMode::Broadcast(index)
167                            | crate::GatherMode::Shuffle(index)
168                            | crate::GatherMode::ShuffleDown(index)
169                            | crate::GatherMode::ShuffleUp(index)
170                            | crate::GatherMode::ShuffleXor(index)
171                            | crate::GatherMode::QuadBroadcast(index) => {
172                                self.expressions_used.insert(index);
173                            }
174                            crate::GatherMode::QuadSwap(_) => {}
175                        }
176                        self.expressions_used.insert(argument);
177                        self.expressions_used.insert(result);
178                    }
179                    St::CooperativeStore { target, ref data } => {
180                        self.expressions_used.insert(target);
181                        self.expressions_used.insert(data.pointer);
182                        self.expressions_used.insert(data.stride);
183                    }
184                    St::RayPipelineFunction(func) => match func {
185                        crate::RayPipelineFunction::TraceRay {
186                            acceleration_structure,
187                            descriptor,
188                            payload,
189                        } => {
190                            self.expressions_used.insert(acceleration_structure);
191                            self.expressions_used.insert(descriptor);
192                            self.expressions_used.insert(payload);
193                        }
194                    },
195                    St::DebugPrintf {
196                        format: _,
197                        ref arguments,
198                    } => {
199                        for &expr in arguments {
200                            self.expressions_used.insert(expr);
201                        }
202                    }
203
204                    // Trivial statements.
205                    St::Break
206                    | St::Continue
207                    | St::Kill
208                    | St::ControlBarrier(_)
209                    | St::MemoryBarrier(_)
210                    | St::Return { value: None } => {}
211                }
212            }
213        }
214    }
215
216    fn trace_atomic_function(&mut self, fun: &crate::AtomicFunction) {
217        use crate::AtomicFunction as Af;
218        match *fun {
219            Af::Exchange {
220                compare: Some(expr),
221            } => {
222                self.expressions_used.insert(expr);
223            }
224            Af::Exchange { compare: None }
225            | Af::Add
226            | Af::Subtract
227            | Af::And
228            | Af::ExclusiveOr
229            | Af::InclusiveOr
230            | Af::Min
231            | Af::Max => {}
232        }
233    }
234
235    fn trace_ray_query_function(&mut self, fun: &crate::RayQueryFunction) {
236        use crate::RayQueryFunction as Qf;
237        match *fun {
238            Qf::Initialize {
239                acceleration_structure,
240                descriptor,
241            } => {
242                self.expressions_used.insert(acceleration_structure);
243                self.expressions_used.insert(descriptor);
244            }
245            Qf::Proceed { result } => {
246                self.expressions_used.insert(result);
247            }
248            Qf::GenerateIntersection { hit_t } => {
249                self.expressions_used.insert(hit_t);
250            }
251            Qf::ConfirmIntersection => {}
252            Qf::Terminate => {}
253            Qf::Begin => {}
254        }
255    }
256}
257
258impl FunctionMap {
259    /// Adjust statements in the body of `function`.
260    ///
261    /// Adjusts expressions using `self.expressions`, and adjusts calls to other
262    /// functions using `function_map`.
263    pub fn adjust_body(
264        &self,
265        function: &mut crate::Function,
266        function_map: &HandleMap<crate::Function>,
267    ) {
268        let block = &mut function.body;
269        let mut worklist: Vec<&mut [crate::Statement]> = vec![block];
270        let adjust = |handle: &mut Handle<crate::Expression>| {
271            self.expressions.adjust(handle);
272        };
273        while let Some(last) = worklist.pop() {
274            for stmt in last {
275                use crate::Statement as St;
276                match *stmt {
277                    St::Emit(ref mut range) => {
278                        self.expressions.adjust_range(range, &function.expressions);
279                    }
280                    St::Block(ref mut block) => worklist.push(block),
281                    St::If {
282                        ref mut condition,
283                        ref mut accept,
284                        ref mut reject,
285                    } => {
286                        adjust(condition);
287                        worklist.push(accept);
288                        worklist.push(reject);
289                    }
290                    St::Switch {
291                        ref mut selector,
292                        ref mut cases,
293                    } => {
294                        adjust(selector);
295                        for case in cases {
296                            worklist.push(&mut case.body);
297                        }
298                    }
299                    St::Loop {
300                        ref mut body,
301                        ref mut continuing,
302                        ref mut break_if,
303                    } => {
304                        if let Some(ref mut break_if) = *break_if {
305                            adjust(break_if);
306                        }
307                        worklist.push(body);
308                        worklist.push(continuing);
309                    }
310                    St::Return {
311                        value: Some(ref mut value),
312                    } => adjust(value),
313                    St::Store {
314                        ref mut pointer,
315                        ref mut value,
316                    } => {
317                        adjust(pointer);
318                        adjust(value);
319                    }
320                    St::ImageStore {
321                        ref mut image,
322                        ref mut coordinate,
323                        ref mut array_index,
324                        ref mut value,
325                    } => {
326                        adjust(image);
327                        adjust(coordinate);
328                        if let Some(ref mut array_index) = *array_index {
329                            adjust(array_index);
330                        }
331                        adjust(value);
332                    }
333                    St::Atomic {
334                        ref mut pointer,
335                        ref mut fun,
336                        ref mut value,
337                        ref mut result,
338                    } => {
339                        adjust(pointer);
340                        self.adjust_atomic_function(fun);
341                        adjust(value);
342                        if let Some(ref mut result) = *result {
343                            adjust(result);
344                        }
345                    }
346                    St::ImageAtomic {
347                        ref mut image,
348                        ref mut coordinate,
349                        ref mut array_index,
350                        fun: _,
351                        ref mut value,
352                    } => {
353                        adjust(image);
354                        adjust(coordinate);
355                        if let Some(ref mut array_index) = *array_index {
356                            adjust(array_index);
357                        }
358                        adjust(value);
359                    }
360                    St::WorkGroupUniformLoad {
361                        ref mut pointer,
362                        ref mut result,
363                    } => {
364                        adjust(pointer);
365                        adjust(result);
366                    }
367                    St::Call {
368                        ref mut function,
369                        ref mut arguments,
370                        ref mut result,
371                    } => {
372                        function_map.adjust(function);
373                        for expr in arguments {
374                            adjust(expr);
375                        }
376                        if let Some(ref mut result) = *result {
377                            adjust(result);
378                        }
379                    }
380                    St::RayQuery {
381                        ref mut query,
382                        ref mut fun,
383                    } => {
384                        adjust(query);
385                        self.adjust_ray_query_function(fun);
386                    }
387                    St::SubgroupBallot {
388                        ref mut result,
389                        ref mut predicate,
390                    } => {
391                        if let Some(ref mut predicate) = *predicate {
392                            adjust(predicate);
393                        }
394                        adjust(result);
395                    }
396                    St::SubgroupCollectiveOperation {
397                        op: _,
398                        collective_op: _,
399                        ref mut argument,
400                        ref mut result,
401                    } => {
402                        adjust(argument);
403                        adjust(result);
404                    }
405                    St::SubgroupGather {
406                        ref mut mode,
407                        ref mut argument,
408                        ref mut result,
409                    } => {
410                        match *mode {
411                            crate::GatherMode::BroadcastFirst => {}
412                            crate::GatherMode::Broadcast(ref mut index)
413                            | crate::GatherMode::Shuffle(ref mut index)
414                            | crate::GatherMode::ShuffleDown(ref mut index)
415                            | crate::GatherMode::ShuffleUp(ref mut index)
416                            | crate::GatherMode::ShuffleXor(ref mut index)
417                            | crate::GatherMode::QuadBroadcast(ref mut index) => adjust(index),
418                            crate::GatherMode::QuadSwap(_) => {}
419                        }
420                        adjust(argument);
421                        adjust(result);
422                    }
423                    St::CooperativeStore {
424                        ref mut target,
425                        ref mut data,
426                    } => {
427                        adjust(target);
428                        adjust(&mut data.pointer);
429                        adjust(&mut data.stride);
430                    }
431                    St::RayPipelineFunction(ref mut func) => match *func {
432                        crate::RayPipelineFunction::TraceRay {
433                            ref mut acceleration_structure,
434                            ref mut descriptor,
435                            ref mut payload,
436                        } => {
437                            adjust(acceleration_structure);
438                            adjust(descriptor);
439                            adjust(payload);
440                        }
441                    },
442                    St::DebugPrintf {
443                        format: _,
444                        ref mut arguments,
445                    } => {
446                        for expr in arguments {
447                            adjust(expr);
448                        }
449                    }
450
451                    // Trivial statements.
452                    St::Break
453                    | St::Continue
454                    | St::Kill
455                    | St::ControlBarrier(_)
456                    | St::MemoryBarrier(_)
457                    | St::Return { value: None } => {}
458                }
459            }
460        }
461    }
462
463    fn adjust_atomic_function(&self, fun: &mut crate::AtomicFunction) {
464        use crate::AtomicFunction as Af;
465        match *fun {
466            Af::Exchange {
467                compare: Some(ref mut expr),
468            } => {
469                self.expressions.adjust(expr);
470            }
471            Af::Exchange { compare: None }
472            | Af::Add
473            | Af::Subtract
474            | Af::And
475            | Af::ExclusiveOr
476            | Af::InclusiveOr
477            | Af::Min
478            | Af::Max => {}
479        }
480    }
481
482    fn adjust_ray_query_function(&self, fun: &mut crate::RayQueryFunction) {
483        use crate::RayQueryFunction as Qf;
484        match *fun {
485            Qf::Initialize {
486                ref mut acceleration_structure,
487                ref mut descriptor,
488            } => {
489                self.expressions.adjust(acceleration_structure);
490                self.expressions.adjust(descriptor);
491            }
492            Qf::Proceed { ref mut result } => {
493                self.expressions.adjust(result);
494            }
495            Qf::GenerateIntersection { ref mut hit_t } => {
496                self.expressions.adjust(hit_t);
497            }
498            Qf::ConfirmIntersection => {}
499            Qf::Terminate => {}
500            Qf::Begin => {}
501        }
502    }
503}