naga/front/spv/
mod.rs

1/*!
2Frontend for [SPIR-V][spv] (Standard Portable Intermediate Representation).
3
4## ID lookups
5
6Our IR links to everything with `Handle`, while SPIR-V uses IDs.
7In order to keep track of the associations, the parser has many lookup tables.
8There map `spv::Word` into a specific IR handle, plus potentially a bit of
9extra info, such as the related SPIR-V type ID.
10TODO: would be nice to find ways that avoid looking up as much
11
12## Inputs/Outputs
13
14We create a private variable for each input/output. The relevant inputs are
15populated at the start of an entry point. The outputs are saved at the end.
16
17The function associated with an entry point is wrapped in another function,
18such that we can handle any `Return` statements without problems.
19
20## Row-major matrices
21
22We don't handle them natively, since the IR only expects column majority.
23Instead, we detect when such matrix is accessed in the `OpAccessChain`,
24and we generate a parallel expression that loads the value, but transposed.
25This value then gets used instead of `OpLoad` result later on.
26
27[spv]: https://www.khronos.org/registry/SPIR-V/
28*/
29
30mod convert;
31mod error;
32mod function;
33mod image;
34mod next_block;
35mod null;
36
37pub use error::Error;
38
39use alloc::{borrow::ToOwned, string::String, vec, vec::Vec};
40use core::{convert::TryInto, mem, num::NonZeroU32};
41
42use half::f16;
43use petgraph::graphmap::GraphMap;
44
45use super::atomic_upgrade::Upgrades;
46use crate::{
47    arena::{Arena, Handle, UniqueArena},
48    proc::{Alignment, Layouter},
49    FastHashMap, FastHashSet, FastIndexMap,
50};
51use convert::*;
52use function::*;
53
54pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[
55    spirv::Capability::Shader,
56    spirv::Capability::VulkanMemoryModel,
57    spirv::Capability::ClipDistance,
58    spirv::Capability::CullDistance,
59    spirv::Capability::SampleRateShading,
60    spirv::Capability::DerivativeControl,
61    spirv::Capability::Matrix,
62    spirv::Capability::ImageQuery,
63    spirv::Capability::Sampled1D,
64    spirv::Capability::Image1D,
65    spirv::Capability::SampledCubeArray,
66    spirv::Capability::ImageCubeArray,
67    spirv::Capability::StorageImageExtendedFormats,
68    spirv::Capability::Int8,
69    spirv::Capability::Int16,
70    spirv::Capability::Int64,
71    spirv::Capability::Int64Atomics,
72    spirv::Capability::Float16,
73    spirv::Capability::AtomicFloat32AddEXT,
74    spirv::Capability::Float64,
75    spirv::Capability::Geometry,
76    spirv::Capability::MultiView,
77    spirv::Capability::StorageBuffer16BitAccess,
78    spirv::Capability::UniformAndStorageBuffer16BitAccess,
79    spirv::Capability::GroupNonUniform,
80    spirv::Capability::GroupNonUniformVote,
81    spirv::Capability::GroupNonUniformArithmetic,
82    spirv::Capability::GroupNonUniformBallot,
83    spirv::Capability::GroupNonUniformShuffle,
84    spirv::Capability::GroupNonUniformShuffleRelative,
85    spirv::Capability::RuntimeDescriptorArray,
86    spirv::Capability::StorageImageMultisample,
87    spirv::Capability::FragmentBarycentricKHR,
88    // tricky ones
89    spirv::Capability::UniformBufferArrayDynamicIndexing,
90    spirv::Capability::StorageBufferArrayDynamicIndexing,
91];
92pub const SUPPORTED_EXTENSIONS: &[&str] = &[
93    "SPV_KHR_storage_buffer_storage_class",
94    "SPV_KHR_vulkan_memory_model",
95    "SPV_KHR_multiview",
96    "SPV_EXT_descriptor_indexing",
97    "SPV_EXT_shader_atomic_float_add",
98    "SPV_KHR_16bit_storage",
99    "SPV_KHR_non_semantic_info",
100    "SPV_KHR_fragment_shader_barycentric",
101];
102
103#[derive(Copy, Clone)]
104pub struct Instruction {
105    op: spirv::Op,
106    wc: u16,
107}
108
109impl Instruction {
110    const fn expect(self, count: u16) -> Result<(), Error> {
111        if self.wc == count {
112            Ok(())
113        } else {
114            Err(Error::InvalidOperandCount(self.op, self.wc))
115        }
116    }
117
118    fn expect_at_least(self, count: u16) -> Result<u16, Error> {
119        self.wc
120            .checked_sub(count)
121            .ok_or(Error::InvalidOperandCount(self.op, self.wc))
122    }
123}
124
125impl crate::TypeInner {
126    fn can_comparison_sample(&self, module: &crate::Module) -> bool {
127        match *self {
128            crate::TypeInner::Image {
129                class:
130                    crate::ImageClass::Sampled {
131                        kind: crate::ScalarKind::Float,
132                        multi: false,
133                    },
134                ..
135            } => true,
136            crate::TypeInner::Sampler { .. } => true,
137            crate::TypeInner::BindingArray { base, .. } => {
138                module.types[base].inner.can_comparison_sample(module)
139            }
140            _ => false,
141        }
142    }
143}
144
145#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
146pub enum ModuleState {
147    Empty,
148    Capability,
149    Extension,
150    ExtInstImport,
151    MemoryModel,
152    EntryPoint,
153    ExecutionMode,
154    Source,
155    Name,
156    ModuleProcessed,
157    Annotation,
158    Type,
159    Function,
160}
161
162trait LookupHelper {
163    type Target;
164    fn lookup(&self, key: spirv::Word) -> Result<&Self::Target, Error>;
165}
166
167impl<T> LookupHelper for FastHashMap<spirv::Word, T> {
168    type Target = T;
169    fn lookup(&self, key: spirv::Word) -> Result<&T, Error> {
170        self.get(&key).ok_or(Error::InvalidId(key))
171    }
172}
173
174impl crate::ImageDimension {
175    const fn required_coordinate_size(&self) -> Option<crate::VectorSize> {
176        match *self {
177            crate::ImageDimension::D1 => None,
178            crate::ImageDimension::D2 => Some(crate::VectorSize::Bi),
179            crate::ImageDimension::D3 => Some(crate::VectorSize::Tri),
180            crate::ImageDimension::Cube => Some(crate::VectorSize::Tri),
181        }
182    }
183}
184
185type MemberIndex = u32;
186
187bitflags::bitflags! {
188    #[derive(Clone, Copy, Debug, Default)]
189    struct DecorationFlags: u32 {
190        const NON_READABLE = 0x1;
191        const NON_WRITABLE = 0x2;
192        const COHERENT = 0x4;
193        const VOLATILE = 0x8;
194    }
195}
196
197impl DecorationFlags {
198    fn to_storage_access(self) -> crate::StorageAccess {
199        let mut access = crate::StorageAccess::LOAD | crate::StorageAccess::STORE;
200        if self.contains(DecorationFlags::NON_READABLE) {
201            access &= !crate::StorageAccess::LOAD;
202        }
203        if self.contains(DecorationFlags::NON_WRITABLE) {
204            access &= !crate::StorageAccess::STORE;
205        }
206        access
207    }
208
209    fn to_memory_decorations(self) -> crate::MemoryDecorations {
210        let mut decorations = crate::MemoryDecorations::empty();
211        if self.contains(DecorationFlags::COHERENT) {
212            decorations |= crate::MemoryDecorations::COHERENT;
213        }
214        if self.contains(DecorationFlags::VOLATILE) {
215            decorations |= crate::MemoryDecorations::VOLATILE;
216        }
217        decorations
218    }
219}
220
221#[derive(Debug, PartialEq)]
222enum Majority {
223    Column,
224    Row,
225}
226
227#[derive(Debug, Default)]
228struct Decoration {
229    name: Option<String>,
230    built_in: Option<spirv::Word>,
231    location: Option<spirv::Word>,
232    index: Option<spirv::Word>,
233    desc_set: Option<spirv::Word>,
234    desc_index: Option<spirv::Word>,
235    specialization_constant_id: Option<spirv::Word>,
236    storage_buffer: bool,
237    offset: Option<spirv::Word>,
238    array_stride: Option<NonZeroU32>,
239    matrix_stride: Option<NonZeroU32>,
240    matrix_major: Option<Majority>,
241    invariant: bool,
242    interpolation: Option<crate::Interpolation>,
243    sampling: Option<crate::Sampling>,
244    flags: DecorationFlags,
245}
246
247impl Decoration {
248    const fn debug_name(&self) -> &str {
249        match self.name {
250            Some(ref name) => name.as_str(),
251            None => "?",
252        }
253    }
254
255    const fn resource_binding(&self) -> Option<crate::ResourceBinding> {
256        match *self {
257            Decoration {
258                desc_set: Some(group),
259                desc_index: Some(binding),
260                ..
261            } => Some(crate::ResourceBinding { group, binding }),
262            _ => None,
263        }
264    }
265
266    fn io_binding(&self) -> Result<crate::Binding, Error> {
267        match *self {
268            Decoration {
269                built_in: Some(built_in),
270                location: None,
271                invariant,
272                ..
273            } => Ok(crate::Binding::BuiltIn(map_builtin(built_in, invariant)?)),
274            Decoration {
275                built_in: None,
276                location: Some(location),
277                index: Some(index),
278                ..
279            } => Ok(crate::Binding::Location {
280                location,
281                interpolation: None,
282                sampling: None,
283                blend_src: Some(index),
284                per_primitive: false,
285            }),
286            Decoration {
287                built_in: None,
288                location: Some(location),
289                interpolation,
290                sampling,
291                ..
292            } => Ok(crate::Binding::Location {
293                location,
294                interpolation,
295                sampling,
296                blend_src: None,
297                per_primitive: false,
298            }),
299            _ => Err(Error::MissingDecoration(spirv::Decoration::Location)),
300        }
301    }
302}
303
304#[derive(Debug)]
305struct LookupFunctionType {
306    parameter_type_ids: Vec<spirv::Word>,
307    return_type_id: spirv::Word,
308}
309
310struct LookupFunction {
311    handle: Handle<crate::Function>,
312    parameters_sampling: Vec<image::SamplingFlags>,
313}
314
315#[derive(Debug)]
316struct EntryPoint {
317    stage: crate::ShaderStage,
318    name: String,
319    early_depth_test: Option<crate::EarlyDepthTest>,
320    workgroup_size: [u32; 3],
321    variable_ids: Vec<spirv::Word>,
322}
323
324#[derive(Clone, Debug)]
325struct LookupType {
326    handle: Handle<crate::Type>,
327    base_id: Option<spirv::Word>,
328}
329
330#[derive(Debug)]
331enum Constant {
332    Constant(Handle<crate::Constant>),
333    Override(Handle<crate::Override>),
334}
335
336impl Constant {
337    const fn to_expr(&self) -> crate::Expression {
338        match *self {
339            Self::Constant(c) => crate::Expression::Constant(c),
340            Self::Override(o) => crate::Expression::Override(o),
341        }
342    }
343}
344
345#[derive(Debug)]
346struct LookupConstant {
347    inner: Constant,
348    type_id: spirv::Word,
349}
350
351#[derive(Debug)]
352enum Variable {
353    Global,
354    Input(crate::FunctionArgument),
355    Output(crate::FunctionResult),
356}
357
358#[derive(Debug)]
359struct LookupVariable {
360    inner: Variable,
361    handle: Handle<crate::GlobalVariable>,
362    type_id: spirv::Word,
363}
364
365/// Information about SPIR-V result ids, stored in `Frontend::lookup_expression`.
366#[derive(Clone, Debug)]
367struct LookupExpression {
368    /// The `Expression` constructed for this result.
369    ///
370    /// Note that, while a SPIR-V result id can be used in any block dominated
371    /// by its definition, a Naga `Expression` is only in scope for the rest of
372    /// its subtree. `Frontend::get_expr_handle` takes care of spilling the result
373    /// to a `LocalVariable` which can then be used anywhere.
374    handle: Handle<crate::Expression>,
375
376    /// The SPIR-V type of this result.
377    type_id: spirv::Word,
378
379    /// The label id of the block that defines this expression.
380    ///
381    /// This is zero for globals, constants, and function parameters, since they
382    /// originate outside any function's block.
383    block_id: spirv::Word,
384}
385
386#[derive(Debug)]
387struct LookupMember {
388    type_id: spirv::Word,
389    // This is true for either matrices, or arrays of matrices (yikes).
390    row_major: bool,
391}
392
393#[derive(Clone, Debug)]
394enum LookupLoadOverride {
395    /// For arrays of matrices, we track them but not loading yet.
396    Pending,
397    /// For matrices, vectors, and scalars, we pre-load the data.
398    Loaded(Handle<crate::Expression>),
399}
400
401#[derive(PartialEq)]
402enum ExtendedClass {
403    Global(crate::AddressSpace),
404    Input,
405    Output,
406}
407
408#[derive(Clone, Debug)]
409pub struct Options {
410    /// The IR coordinate space matches all the APIs except SPIR-V,
411    /// so by default we flip the Y coordinate of the `BuiltIn::Position`.
412    /// This flag can be used to avoid this.
413    pub adjust_coordinate_space: bool,
414    /// Only allow shaders with the known set of capabilities.
415    pub strict_capabilities: bool,
416    pub block_ctx_dump_prefix: Option<String>,
417}
418
419impl Default for Options {
420    fn default() -> Self {
421        Options {
422            adjust_coordinate_space: true,
423            strict_capabilities: true,
424            block_ctx_dump_prefix: None,
425        }
426    }
427}
428
429/// An index into the `BlockContext::bodies` table.
430type BodyIndex = usize;
431
432/// An intermediate representation of a Naga [`Statement`].
433///
434/// `Body` and `BodyFragment` values form a tree: the `BodyIndex` fields of the
435/// variants are indices of the child `Body` values in [`BlockContext::bodies`].
436/// The `lower` function assembles the final `Statement` tree from this `Body`
437/// tree. See [`BlockContext`] for details.
438///
439/// [`Statement`]: crate::Statement
440#[derive(Debug)]
441enum BodyFragment {
442    BlockId(spirv::Word),
443    If {
444        condition: Handle<crate::Expression>,
445        accept: BodyIndex,
446        reject: BodyIndex,
447    },
448    Loop {
449        /// The body of the loop. Its [`Body::parent`] is the block containing
450        /// this `Loop` fragment.
451        body: BodyIndex,
452
453        /// The loop's continuing block. This is a grandchild: its
454        /// [`Body::parent`] is the loop body block, whose index is above.
455        continuing: BodyIndex,
456
457        /// If the SPIR-V loop's back-edge branch is conditional, this is the
458        /// expression that must be `false` for the back-edge to be taken, with
459        /// `true` being for the "loop merge" (which breaks out of the loop).
460        break_if: Option<Handle<crate::Expression>>,
461    },
462    Switch {
463        selector: Handle<crate::Expression>,
464        cases: Vec<(i32, BodyIndex)>,
465        default: BodyIndex,
466    },
467    Break,
468    Continue,
469}
470
471/// An intermediate representation of a Naga [`Block`].
472///
473/// This will be assembled into a `Block` once we've added spills for phi nodes
474/// and out-of-scope expressions. See [`BlockContext`] for details.
475///
476/// [`Block`]: crate::Block
477#[derive(Debug)]
478struct Body {
479    /// The index of the direct parent of this body
480    parent: usize,
481    data: Vec<BodyFragment>,
482}
483
484impl Body {
485    /// Creates a new empty `Body` with the specified `parent`
486    pub const fn with_parent(parent: usize) -> Self {
487        Body {
488            parent,
489            data: Vec::new(),
490        }
491    }
492}
493
494#[derive(Debug)]
495struct PhiExpression {
496    /// The local variable used for the phi node
497    local: Handle<crate::LocalVariable>,
498    /// List of (expression, block)
499    expressions: Vec<(spirv::Word, spirv::Word)>,
500}
501
502#[derive(Copy, Clone, Debug, PartialEq, Eq)]
503enum MergeBlockInformation {
504    LoopMerge,
505    LoopContinue,
506    SelectionMerge,
507    SwitchMerge,
508}
509
510/// Fragments of Naga IR, to be assembled into `Statements` once data flow is
511/// resolved.
512///
513/// We can't build a Naga `Statement` tree directly from SPIR-V blocks for three
514/// main reasons:
515///
516/// - We parse a function's SPIR-V blocks in the order they appear in the file.
517///   Within a function, SPIR-V requires that a block must precede any blocks it
518///   structurally dominates, but doesn't say much else about the order in which
519///   they must appear. So while we know we'll see control flow header blocks
520///   before their child constructs and merge blocks, those children and the
521///   merge blocks may appear in any order - perhaps even intermingled with
522///   children of other constructs.
523///
524/// - A SPIR-V expression can be used in any SPIR-V block dominated by its
525///   definition, whereas Naga expressions are scoped to the rest of their
526///   subtree. This means that discovering an expression use later in the
527///   function retroactively requires us to have spilled that expression into a
528///   local variable back before we left its scope. (The docs for
529///   [`Frontend::get_expr_handle`] explain this in more detail.)
530///
531/// - We translate SPIR-V OpPhi expressions as Naga local variables in which we
532///   store the appropriate value before jumping to the OpPhi's block.
533///
534/// All these cases require us to go back and amend previously generated Naga IR
535/// based on things we discover later. But modifying old blocks in arbitrary
536/// spots in a `Statement` tree is awkward.
537///
538/// Instead, as we iterate through the function's body, we accumulate
539/// control-flow-free fragments of Naga IR in the [`blocks`] table, while
540/// building a skeleton of the Naga `Statement` tree in [`bodies`]. We note any
541/// spills and temporaries we must introduce in [`phis`].
542///
543/// Finally, once we've processed the entire function, we add temporaries and
544/// spills to the fragmentary `Blocks` as directed by `phis`, and assemble them
545/// into the final Naga `Statement` tree as directed by `bodies`.
546///
547/// [`blocks`]: BlockContext::blocks
548/// [`bodies`]: BlockContext::bodies
549/// [`phis`]: BlockContext::phis
550#[derive(Debug)]
551struct BlockContext<'function> {
552    /// Phi nodes encountered when parsing the function, used to generate spills
553    /// to local variables.
554    phis: Vec<PhiExpression>,
555
556    /// Fragments of control-flow-free Naga IR.
557    ///
558    /// These will be stitched together into a proper [`Statement`] tree according
559    /// to `bodies`, once parsing is complete.
560    ///
561    /// [`Statement`]: crate::Statement
562    blocks: FastHashMap<spirv::Word, crate::Block>,
563
564    /// Map from each SPIR-V block's label id to the index of the [`Body`] in
565    /// [`bodies`] the block should append its contents to.
566    ///
567    /// Since each statement in a Naga [`Block`] dominates the next, we are sure
568    /// to encounter their SPIR-V blocks in order. Thus, by having this table
569    /// map a SPIR-V structured control flow construct's merge block to the same
570    /// body index as its header block, when we encounter the merge block, we
571    /// will simply pick up building the [`Body`] where the header left off.
572    ///
573    /// A function's first block is special: it is the only block we encounter
574    /// without having seen its label mentioned in advance. (It's simply the
575    /// first `OpLabel` after the `OpFunction`.) We thus assume that any block
576    /// missing an entry here must be the first block, which always has body
577    /// index zero.
578    ///
579    /// [`bodies`]: BlockContext::bodies
580    /// [`Block`]: crate::Block
581    body_for_label: FastHashMap<spirv::Word, BodyIndex>,
582
583    /// SPIR-V metadata about merge/continue blocks.
584    mergers: FastHashMap<spirv::Word, MergeBlockInformation>,
585
586    /// A table of `Body` values, each representing a block in the final IR.
587    ///
588    /// The first element is always the function's top-level block.
589    bodies: Vec<Body>,
590
591    /// The module we're building.
592    module: &'function mut crate::Module,
593
594    /// Id of the function currently being processed
595    function_id: spirv::Word,
596    /// Expression arena of the function currently being processed
597    expressions: &'function mut Arena<crate::Expression>,
598    /// Local variables arena of the function currently being processed
599    local_arena: &'function mut Arena<crate::LocalVariable>,
600    /// Arguments of the function currently being processed
601    arguments: &'function [crate::FunctionArgument],
602    /// Metadata about the usage of function parameters as sampling objects
603    parameter_sampling: &'function mut [image::SamplingFlags],
604}
605
606enum SignAnchor {
607    Result,
608    Operand,
609}
610
611pub struct Frontend<I> {
612    data: I,
613    data_offset: usize,
614    state: ModuleState,
615    layouter: Layouter,
616    temp_bytes: Vec<u8>,
617    ext_glsl_id: Option<spirv::Word>,
618    ext_non_semantic_id: Option<spirv::Word>,
619    future_decor: FastHashMap<spirv::Word, Decoration>,
620    future_member_decor: FastHashMap<(spirv::Word, MemberIndex), Decoration>,
621    lookup_member: FastHashMap<(Handle<crate::Type>, MemberIndex), LookupMember>,
622    handle_sampling: FastHashMap<Handle<crate::GlobalVariable>, image::SamplingFlags>,
623
624    /// A record of what is accessed by [`Atomic`] statements we've
625    /// generated, so we can upgrade the types of their operands.
626    ///
627    /// [`Atomic`]: crate::Statement::Atomic
628    upgrade_atomics: Upgrades,
629
630    lookup_type: FastHashMap<spirv::Word, LookupType>,
631    lookup_void_type: Option<spirv::Word>,
632    lookup_storage_buffer_types: FastHashMap<Handle<crate::Type>, crate::StorageAccess>,
633    lookup_constant: FastHashMap<spirv::Word, LookupConstant>,
634    lookup_variable: FastHashMap<spirv::Word, LookupVariable>,
635    lookup_expression: FastHashMap<spirv::Word, LookupExpression>,
636    // Load overrides are used to work around row-major matrices
637    lookup_load_override: FastHashMap<spirv::Word, LookupLoadOverride>,
638    lookup_sampled_image: FastHashMap<spirv::Word, image::LookupSampledImage>,
639    lookup_function_type: FastHashMap<spirv::Word, LookupFunctionType>,
640    lookup_function: FastHashMap<spirv::Word, LookupFunction>,
641    lookup_entry_point: FastHashMap<spirv::Word, EntryPoint>,
642    // When parsing functions, each entry point function gets an entry here so that additional
643    // processing for them can be performed after all function parsing.
644    deferred_entry_points: Vec<(EntryPoint, spirv::Word)>,
645    //Note: each `OpFunctionCall` gets a single entry here, indexed by the
646    // dummy `Handle<crate::Function>` of the call site.
647    deferred_function_calls: Vec<spirv::Word>,
648    dummy_functions: Arena<crate::Function>,
649    // Graph of all function calls through the module.
650    // It's used to sort the functions (as nodes) topologically,
651    // so that in the IR any called function is already known.
652    function_call_graph: GraphMap<
653        spirv::Word,
654        (),
655        petgraph::Directed,
656        core::hash::BuildHasherDefault<rustc_hash::FxHasher>,
657    >,
658    options: Options,
659
660    /// Maps for a switch from a case target to the respective body and associated literals that
661    /// use that target block id.
662    ///
663    /// Used to preserve allocations between instruction parsing.
664    switch_cases: FastIndexMap<spirv::Word, (BodyIndex, Vec<i32>)>,
665
666    /// Tracks access to gl_PerVertex's builtins, it is used to cull unused builtins since initializing those can
667    /// affect performance and the mere presence of some of these builtins might cause backends to error since they
668    /// might be unsupported.
669    ///
670    /// The problematic builtins are: PointSize, ClipDistance and CullDistance.
671    ///
672    /// glslang declares those by default even though they are never written to
673    /// (see <https://github.com/KhronosGroup/glslang/issues/1868>)
674    gl_per_vertex_builtin_access: FastHashSet<crate::BuiltIn>,
675}
676
677impl<I: Iterator<Item = u32>> Frontend<I> {
678    pub fn new(data: I, options: &Options) -> Self {
679        Frontend {
680            data,
681            data_offset: 0,
682            state: ModuleState::Empty,
683            layouter: Layouter::default(),
684            temp_bytes: Vec::new(),
685            ext_glsl_id: None,
686            ext_non_semantic_id: None,
687            future_decor: FastHashMap::default(),
688            future_member_decor: FastHashMap::default(),
689            handle_sampling: FastHashMap::default(),
690            lookup_member: FastHashMap::default(),
691            upgrade_atomics: Default::default(),
692            lookup_type: FastHashMap::default(),
693            lookup_void_type: None,
694            lookup_storage_buffer_types: FastHashMap::default(),
695            lookup_constant: FastHashMap::default(),
696            lookup_variable: FastHashMap::default(),
697            lookup_expression: FastHashMap::default(),
698            lookup_load_override: FastHashMap::default(),
699            lookup_sampled_image: FastHashMap::default(),
700            lookup_function_type: FastHashMap::default(),
701            lookup_function: FastHashMap::default(),
702            lookup_entry_point: FastHashMap::default(),
703            deferred_entry_points: Vec::default(),
704            deferred_function_calls: Vec::default(),
705            dummy_functions: Arena::new(),
706            function_call_graph: GraphMap::new(),
707            options: options.clone(),
708            switch_cases: FastIndexMap::default(),
709            gl_per_vertex_builtin_access: FastHashSet::default(),
710        }
711    }
712
713    fn span_from(&self, from: usize) -> crate::Span {
714        crate::Span::from(from..self.data_offset)
715    }
716
717    fn span_from_with_op(&self, from: usize) -> crate::Span {
718        crate::Span::from((from - 4)..self.data_offset)
719    }
720
721    fn next(&mut self) -> Result<u32, Error> {
722        if let Some(res) = self.data.next() {
723            self.data_offset += 4;
724            Ok(res)
725        } else {
726            Err(Error::IncompleteData)
727        }
728    }
729
730    fn next_inst(&mut self) -> Result<Instruction, Error> {
731        let word = self.next()?;
732        let (wc, opcode) = ((word >> 16) as u16, (word & 0xffff) as u16);
733        if wc == 0 {
734            return Err(Error::InvalidWordCount);
735        }
736        let op = spirv::Op::from_u32(opcode as u32).ok_or(Error::UnknownInstruction(opcode))?;
737
738        Ok(Instruction { op, wc })
739    }
740
741    fn next_string(&mut self, mut count: u16) -> Result<(String, u16), Error> {
742        self.temp_bytes.clear();
743        loop {
744            if count == 0 {
745                return Err(Error::BadString);
746            }
747            count -= 1;
748            let chars = self.next()?.to_le_bytes();
749            let pos = chars.iter().position(|&c| c == 0).unwrap_or(4);
750            self.temp_bytes.extend_from_slice(&chars[..pos]);
751            if pos < 4 {
752                break;
753            }
754        }
755        core::str::from_utf8(&self.temp_bytes)
756            .map(|s| (s.to_owned(), count))
757            .map_err(|_| Error::BadString)
758    }
759
760    fn next_decoration(
761        &mut self,
762        inst: Instruction,
763        base_words: u16,
764        dec: &mut Decoration,
765    ) -> Result<(), Error> {
766        let raw = self.next()?;
767        let dec_typed = spirv::Decoration::from_u32(raw).ok_or(Error::InvalidDecoration(raw))?;
768        log::trace!("\t\t{}: {:?}", dec.debug_name(), dec_typed);
769        match dec_typed {
770            spirv::Decoration::BuiltIn => {
771                inst.expect(base_words + 2)?;
772                dec.built_in = Some(self.next()?);
773            }
774            spirv::Decoration::Location => {
775                inst.expect(base_words + 2)?;
776                dec.location = Some(self.next()?);
777            }
778            spirv::Decoration::Index => {
779                inst.expect(base_words + 2)?;
780                dec.index = Some(self.next()?);
781            }
782            spirv::Decoration::DescriptorSet => {
783                inst.expect(base_words + 2)?;
784                dec.desc_set = Some(self.next()?);
785            }
786            spirv::Decoration::Binding => {
787                inst.expect(base_words + 2)?;
788                dec.desc_index = Some(self.next()?);
789            }
790            spirv::Decoration::BufferBlock => {
791                dec.storage_buffer = true;
792            }
793            spirv::Decoration::Offset => {
794                inst.expect(base_words + 2)?;
795                dec.offset = Some(self.next()?);
796            }
797            spirv::Decoration::ArrayStride => {
798                inst.expect(base_words + 2)?;
799                dec.array_stride = NonZeroU32::new(self.next()?);
800            }
801            spirv::Decoration::MatrixStride => {
802                inst.expect(base_words + 2)?;
803                dec.matrix_stride = NonZeroU32::new(self.next()?);
804            }
805            spirv::Decoration::Invariant => {
806                dec.invariant = true;
807            }
808            spirv::Decoration::NoPerspective => {
809                dec.interpolation = Some(crate::Interpolation::Linear);
810            }
811            spirv::Decoration::Flat => {
812                dec.interpolation = Some(crate::Interpolation::Flat);
813            }
814            spirv::Decoration::PerVertexKHR => {
815                dec.interpolation = Some(crate::Interpolation::PerVertex);
816            }
817            spirv::Decoration::Centroid => {
818                dec.sampling = Some(crate::Sampling::Centroid);
819            }
820            spirv::Decoration::Sample => {
821                dec.sampling = Some(crate::Sampling::Sample);
822            }
823            spirv::Decoration::NonReadable => {
824                dec.flags |= DecorationFlags::NON_READABLE;
825            }
826            spirv::Decoration::NonWritable => {
827                dec.flags |= DecorationFlags::NON_WRITABLE;
828            }
829            spirv::Decoration::Coherent => {
830                dec.flags |= DecorationFlags::COHERENT;
831            }
832            spirv::Decoration::Volatile => {
833                dec.flags |= DecorationFlags::VOLATILE;
834            }
835            spirv::Decoration::ColMajor => {
836                dec.matrix_major = Some(Majority::Column);
837            }
838            spirv::Decoration::RowMajor => {
839                dec.matrix_major = Some(Majority::Row);
840            }
841            spirv::Decoration::SpecId => {
842                dec.specialization_constant_id = Some(self.next()?);
843            }
844            other => {
845                let level = match other {
846                    // Block decorations show up everywhere and we don't
847                    // really care about them, so to prevent log spam
848                    // we demote them to debug level.
849                    spirv::Decoration::Block => log::Level::Debug,
850                    _ => log::Level::Warn,
851                };
852
853                log::log!(level, "Unknown decoration {other:?}");
854                for _ in base_words + 1..inst.wc {
855                    let _var = self.next()?;
856                }
857            }
858        }
859        Ok(())
860    }
861
862    /// Return the Naga [`Expression`] to use in `body_idx` to refer to the SPIR-V result `id`.
863    ///
864    /// Ideally, we would just have a map from each SPIR-V instruction id to the
865    /// [`Handle`] for the Naga [`Expression`] we generated for it.
866    /// Unfortunately, SPIR-V and Naga IR are different enough that such a
867    /// straightforward relationship isn't possible.
868    ///
869    /// In SPIR-V, an instruction's result id can be used by any instruction
870    /// dominated by that instruction. In Naga, an [`Expression`] is only in
871    /// scope for the remainder of its [`Block`]. In pseudocode:
872    ///
873    /// ```ignore
874    ///     loop {
875    ///         a = f();
876    ///         g(a);
877    ///         break;
878    ///     }
879    ///     h(a);
880    /// ```
881    ///
882    /// Suppose the calls to `f`, `g`, and `h` are SPIR-V instructions. In
883    /// SPIR-V, both the `g` and `h` instructions are allowed to refer to `a`,
884    /// because the loop body, including `f`, dominates both of them.
885    ///
886    /// But if `a` is a Naga [`Expression`], its scope ends at the end of the
887    /// block it's evaluated in: the loop body. Thus, while the [`Expression`]
888    /// we generate for `g` can refer to `a`, the one we generate for `h`
889    /// cannot.
890    ///
891    /// Instead, the SPIR-V front end must generate Naga IR like this:
892    ///
893    /// ```ignore
894    ///     var temp; // INTRODUCED
895    ///     loop {
896    ///         a = f();
897    ///         g(a);
898    ///         temp = a; // INTRODUCED
899    ///     }
900    ///     h(temp); // ADJUSTED
901    /// ```
902    ///
903    /// In other words, where `a` is in scope, [`Expression`]s can refer to it
904    /// directly; but once it is out of scope, we need to spill it to a
905    /// temporary and refer to that instead.
906    ///
907    /// Given a SPIR-V expression `id` and the index `body_idx` of the [body]
908    /// that wants to refer to it:
909    ///
910    /// - If the Naga [`Expression`] we generated for `id` is in scope in
911    ///   `body_idx`, then we simply return its `Handle<Expression>`.
912    ///
913    /// - Otherwise, introduce a new [`LocalVariable`], and add an entry to
914    ///   [`BlockContext::phis`] to arrange for `id`'s value to be spilled to
915    ///   it. Then emit a fresh [`Load`] of that temporary variable for use in
916    ///   `body_idx`'s block, and return its `Handle`.
917    ///
918    /// The SPIR-V domination rule ensures that the introduced [`LocalVariable`]
919    /// will always have been initialized before it is used.
920    ///
921    /// `lookup` must be the [`LookupExpression`] for `id`.
922    ///
923    /// `body_idx` argument must be the index of the [`Body`] that hopes to use
924    /// `id`'s [`Expression`].
925    ///
926    /// [`Expression`]: crate::Expression
927    /// [`Handle`]: crate::Handle
928    /// [`Block`]: crate::Block
929    /// [body]: BlockContext::bodies
930    /// [`LocalVariable`]: crate::LocalVariable
931    /// [`Load`]: crate::Expression::Load
932    fn get_expr_handle(
933        &self,
934        id: spirv::Word,
935        lookup: &LookupExpression,
936        ctx: &mut BlockContext,
937        emitter: &mut crate::proc::Emitter,
938        block: &mut crate::Block,
939        body_idx: BodyIndex,
940    ) -> Handle<crate::Expression> {
941        // What `Body` was `id` defined in?
942        let expr_body_idx = ctx
943            .body_for_label
944            .get(&lookup.block_id)
945            .copied()
946            .unwrap_or(0);
947
948        // Don't need to do a load/store if the expression is in the main body
949        // or if the expression is in the same body as where the query was
950        // requested. The body_idx might actually not be the final one if a loop
951        // or conditional occurs but in those cases we know that the new body
952        // will be a subscope of the body that was passed so we can still reuse
953        // the handle and not issue a load/store.
954        if is_parent(body_idx, expr_body_idx, ctx) {
955            lookup.handle
956        } else {
957            // Add a temporary variable of the same type which will be used to
958            // store the original expression and used in the current block
959            let ty = self.lookup_type[&lookup.type_id].handle;
960            let local = ctx.local_arena.append(
961                crate::LocalVariable {
962                    name: None,
963                    ty,
964                    init: None,
965                },
966                crate::Span::default(),
967            );
968
969            block.extend(emitter.finish(ctx.expressions));
970            let pointer = ctx.expressions.append(
971                crate::Expression::LocalVariable(local),
972                crate::Span::default(),
973            );
974            emitter.start(ctx.expressions);
975            let expr = ctx
976                .expressions
977                .append(crate::Expression::Load { pointer }, crate::Span::default());
978
979            // Add a slightly odd entry to the phi table, so that while `id`'s
980            // `Expression` is still in scope, the usual phi processing will
981            // spill its value to `local`, where we can find it later.
982            //
983            // This pretends that the block in which `id` is defined is the
984            // predecessor of some other block with a phi in it that cites id as
985            // one of its sources, and uses `local` as its variable. There is no
986            // such phi, but nobody needs to know that.
987            ctx.phis.push(PhiExpression {
988                local,
989                expressions: vec![(id, lookup.block_id)],
990            });
991
992            expr
993        }
994    }
995
996    fn parse_expr_unary_op(
997        &mut self,
998        ctx: &mut BlockContext,
999        emitter: &mut crate::proc::Emitter,
1000        block: &mut crate::Block,
1001        block_id: spirv::Word,
1002        body_idx: usize,
1003        op: crate::UnaryOperator,
1004    ) -> Result<(), Error> {
1005        let start = self.data_offset;
1006        let result_type_id = self.next()?;
1007        let result_id = self.next()?;
1008        let p_id = self.next()?;
1009
1010        let p_lexp = self.lookup_expression.lookup(p_id)?;
1011        let handle = self.get_expr_handle(p_id, p_lexp, ctx, emitter, block, body_idx);
1012
1013        let expr = crate::Expression::Unary { op, expr: handle };
1014        self.lookup_expression.insert(
1015            result_id,
1016            LookupExpression {
1017                handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
1018                type_id: result_type_id,
1019                block_id,
1020            },
1021        );
1022        Ok(())
1023    }
1024
1025    fn parse_expr_binary_op(
1026        &mut self,
1027        ctx: &mut BlockContext,
1028        emitter: &mut crate::proc::Emitter,
1029        block: &mut crate::Block,
1030        block_id: spirv::Word,
1031        body_idx: usize,
1032        op: crate::BinaryOperator,
1033    ) -> Result<(), Error> {
1034        let start = self.data_offset;
1035        let result_type_id = self.next()?;
1036        let result_id = self.next()?;
1037        let p1_id = self.next()?;
1038        let p2_id = self.next()?;
1039
1040        let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1041        let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1042        let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1043        let right = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1044
1045        let expr = crate::Expression::Binary { op, left, right };
1046        self.lookup_expression.insert(
1047            result_id,
1048            LookupExpression {
1049                handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
1050                type_id: result_type_id,
1051                block_id,
1052            },
1053        );
1054        Ok(())
1055    }
1056
1057    /// A more complicated version of the unary op,
1058    /// where we force the operand to have the same type as the result.
1059    fn parse_expr_unary_op_sign_adjusted(
1060        &mut self,
1061        ctx: &mut BlockContext,
1062        emitter: &mut crate::proc::Emitter,
1063        block: &mut crate::Block,
1064        block_id: spirv::Word,
1065        body_idx: usize,
1066        op: crate::UnaryOperator,
1067    ) -> Result<(), Error> {
1068        let start = self.data_offset;
1069        let result_type_id = self.next()?;
1070        let result_id = self.next()?;
1071        let p1_id = self.next()?;
1072        let span = self.span_from_with_op(start);
1073
1074        let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1075        let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1076
1077        let result_lookup_ty = self.lookup_type.lookup(result_type_id)?;
1078        let kind = ctx.module.types[result_lookup_ty.handle]
1079            .inner
1080            .scalar_kind()
1081            .unwrap();
1082
1083        let expr = crate::Expression::Unary {
1084            op,
1085            expr: if p1_lexp.type_id == result_type_id {
1086                left
1087            } else {
1088                ctx.expressions.append(
1089                    crate::Expression::As {
1090                        expr: left,
1091                        kind,
1092                        convert: None,
1093                    },
1094                    span,
1095                )
1096            },
1097        };
1098
1099        self.lookup_expression.insert(
1100            result_id,
1101            LookupExpression {
1102                handle: ctx.expressions.append(expr, span),
1103                type_id: result_type_id,
1104                block_id,
1105            },
1106        );
1107        Ok(())
1108    }
1109
1110    /// A more complicated version of the binary op,
1111    /// where we force the operand to have the same type as the result.
1112    /// This is mostly needed for "i++" and "i--" coming from GLSL.
1113    #[allow(clippy::too_many_arguments)]
1114    fn parse_expr_binary_op_sign_adjusted(
1115        &mut self,
1116        ctx: &mut BlockContext,
1117        emitter: &mut crate::proc::Emitter,
1118        block: &mut crate::Block,
1119        block_id: spirv::Word,
1120        body_idx: usize,
1121        op: crate::BinaryOperator,
1122        // For arithmetic operations, we need the sign of operands to match the result.
1123        // For boolean operations, however, the operands need to match the signs, but
1124        // result is always different - a boolean.
1125        anchor: SignAnchor,
1126    ) -> Result<(), Error> {
1127        let start = self.data_offset;
1128        let result_type_id = self.next()?;
1129        let result_id = self.next()?;
1130        let p1_id = self.next()?;
1131        let p2_id = self.next()?;
1132        let span = self.span_from_with_op(start);
1133
1134        let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1135        let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1136        let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1137        let right = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1138
1139        let expected_type_id = match anchor {
1140            SignAnchor::Result => result_type_id,
1141            SignAnchor::Operand => p1_lexp.type_id,
1142        };
1143        let expected_lookup_ty = self.lookup_type.lookup(expected_type_id)?;
1144        let kind = ctx.module.types[expected_lookup_ty.handle]
1145            .inner
1146            .scalar_kind()
1147            .unwrap();
1148
1149        let expr = crate::Expression::Binary {
1150            op,
1151            left: if p1_lexp.type_id == expected_type_id {
1152                left
1153            } else {
1154                ctx.expressions.append(
1155                    crate::Expression::As {
1156                        expr: left,
1157                        kind,
1158                        convert: None,
1159                    },
1160                    span,
1161                )
1162            },
1163            right: if p2_lexp.type_id == expected_type_id {
1164                right
1165            } else {
1166                ctx.expressions.append(
1167                    crate::Expression::As {
1168                        expr: right,
1169                        kind,
1170                        convert: None,
1171                    },
1172                    span,
1173                )
1174            },
1175        };
1176
1177        self.lookup_expression.insert(
1178            result_id,
1179            LookupExpression {
1180                handle: ctx.expressions.append(expr, span),
1181                type_id: result_type_id,
1182                block_id,
1183            },
1184        );
1185        Ok(())
1186    }
1187
1188    /// A version of the binary op where one or both of the arguments might need to be casted to a
1189    /// specific integer kind (unsigned or signed), used for operations like OpINotEqual or
1190    /// OpUGreaterThan.
1191    #[allow(clippy::too_many_arguments)]
1192    fn parse_expr_int_comparison(
1193        &mut self,
1194        ctx: &mut BlockContext,
1195        emitter: &mut crate::proc::Emitter,
1196        block: &mut crate::Block,
1197        block_id: spirv::Word,
1198        body_idx: usize,
1199        op: crate::BinaryOperator,
1200        kind: crate::ScalarKind,
1201    ) -> Result<(), Error> {
1202        let start = self.data_offset;
1203        let result_type_id = self.next()?;
1204        let result_id = self.next()?;
1205        let p1_id = self.next()?;
1206        let p2_id = self.next()?;
1207        let span = self.span_from_with_op(start);
1208
1209        let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1210        let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1211        let p1_lookup_ty = self.lookup_type.lookup(p1_lexp.type_id)?;
1212        let p1_kind = ctx.module.types[p1_lookup_ty.handle]
1213            .inner
1214            .scalar_kind()
1215            .unwrap();
1216        let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1217        let right = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1218        let p2_lookup_ty = self.lookup_type.lookup(p2_lexp.type_id)?;
1219        let p2_kind = ctx.module.types[p2_lookup_ty.handle]
1220            .inner
1221            .scalar_kind()
1222            .unwrap();
1223
1224        let expr = crate::Expression::Binary {
1225            op,
1226            left: if p1_kind == kind {
1227                left
1228            } else {
1229                ctx.expressions.append(
1230                    crate::Expression::As {
1231                        expr: left,
1232                        kind,
1233                        convert: None,
1234                    },
1235                    span,
1236                )
1237            },
1238            right: if p2_kind == kind {
1239                right
1240            } else {
1241                ctx.expressions.append(
1242                    crate::Expression::As {
1243                        expr: right,
1244                        kind,
1245                        convert: None,
1246                    },
1247                    span,
1248                )
1249            },
1250        };
1251
1252        self.lookup_expression.insert(
1253            result_id,
1254            LookupExpression {
1255                handle: ctx.expressions.append(expr, span),
1256                type_id: result_type_id,
1257                block_id,
1258            },
1259        );
1260        Ok(())
1261    }
1262
1263    fn parse_expr_shift_op(
1264        &mut self,
1265        ctx: &mut BlockContext,
1266        emitter: &mut crate::proc::Emitter,
1267        block: &mut crate::Block,
1268        block_id: spirv::Word,
1269        body_idx: usize,
1270        op: crate::BinaryOperator,
1271    ) -> Result<(), Error> {
1272        let start = self.data_offset;
1273        let result_type_id = self.next()?;
1274        let result_id = self.next()?;
1275        let p1_id = self.next()?;
1276        let p2_id = self.next()?;
1277
1278        let span = self.span_from_with_op(start);
1279
1280        let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1281        let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1282        let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1283        let p2_handle = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1284        // convert the shift to Uint
1285        let right = ctx.expressions.append(
1286            crate::Expression::As {
1287                expr: p2_handle,
1288                kind: crate::ScalarKind::Uint,
1289                convert: None,
1290            },
1291            span,
1292        );
1293
1294        let expr = crate::Expression::Binary { op, left, right };
1295        self.lookup_expression.insert(
1296            result_id,
1297            LookupExpression {
1298                handle: ctx.expressions.append(expr, span),
1299                type_id: result_type_id,
1300                block_id,
1301            },
1302        );
1303        Ok(())
1304    }
1305
1306    fn parse_expr_derivative(
1307        &mut self,
1308        ctx: &mut BlockContext,
1309        emitter: &mut crate::proc::Emitter,
1310        block: &mut crate::Block,
1311        block_id: spirv::Word,
1312        body_idx: usize,
1313        (axis, ctrl): (crate::DerivativeAxis, crate::DerivativeControl),
1314    ) -> Result<(), Error> {
1315        let start = self.data_offset;
1316        let result_type_id = self.next()?;
1317        let result_id = self.next()?;
1318        let arg_id = self.next()?;
1319
1320        let arg_lexp = self.lookup_expression.lookup(arg_id)?;
1321        let arg_handle = self.get_expr_handle(arg_id, arg_lexp, ctx, emitter, block, body_idx);
1322
1323        let expr = crate::Expression::Derivative {
1324            axis,
1325            ctrl,
1326            expr: arg_handle,
1327        };
1328        self.lookup_expression.insert(
1329            result_id,
1330            LookupExpression {
1331                handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
1332                type_id: result_type_id,
1333                block_id,
1334            },
1335        );
1336        Ok(())
1337    }
1338
1339    #[allow(clippy::too_many_arguments)]
1340    fn insert_composite(
1341        &self,
1342        root_expr: Handle<crate::Expression>,
1343        root_type_id: spirv::Word,
1344        object_expr: Handle<crate::Expression>,
1345        selections: &[spirv::Word],
1346        type_arena: &UniqueArena<crate::Type>,
1347        expressions: &mut Arena<crate::Expression>,
1348        span: crate::Span,
1349    ) -> Result<Handle<crate::Expression>, Error> {
1350        let selection = match selections.first() {
1351            Some(&index) => index,
1352            None => return Ok(object_expr),
1353        };
1354        let root_span = expressions.get_span(root_expr);
1355        let root_lookup = self.lookup_type.lookup(root_type_id)?;
1356
1357        let (count, child_type_id) = match type_arena[root_lookup.handle].inner {
1358            crate::TypeInner::Struct { ref members, .. } => {
1359                let child_member = self
1360                    .lookup_member
1361                    .get(&(root_lookup.handle, selection))
1362                    .ok_or(Error::InvalidAccessType(root_type_id))?;
1363                (members.len(), child_member.type_id)
1364            }
1365            crate::TypeInner::Array { size, .. } => {
1366                let size = match size {
1367                    crate::ArraySize::Constant(size) => size.get(),
1368                    crate::ArraySize::Pending(_) => {
1369                        unreachable!();
1370                    }
1371                    // A runtime sized array is not a composite type
1372                    crate::ArraySize::Dynamic => {
1373                        return Err(Error::InvalidAccessType(root_type_id))
1374                    }
1375                };
1376
1377                let child_type_id = root_lookup
1378                    .base_id
1379                    .ok_or(Error::InvalidAccessType(root_type_id))?;
1380
1381                (size as usize, child_type_id)
1382            }
1383            crate::TypeInner::Vector { size, .. }
1384            | crate::TypeInner::Matrix { columns: size, .. } => {
1385                let child_type_id = root_lookup
1386                    .base_id
1387                    .ok_or(Error::InvalidAccessType(root_type_id))?;
1388                (size as usize, child_type_id)
1389            }
1390            _ => return Err(Error::InvalidAccessType(root_type_id)),
1391        };
1392
1393        let mut components = Vec::with_capacity(count);
1394        for index in 0..count as u32 {
1395            let expr = expressions.append(
1396                crate::Expression::AccessIndex {
1397                    base: root_expr,
1398                    index,
1399                },
1400                if index == selection { span } else { root_span },
1401            );
1402            components.push(expr);
1403        }
1404        components[selection as usize] = self.insert_composite(
1405            components[selection as usize],
1406            child_type_id,
1407            object_expr,
1408            &selections[1..],
1409            type_arena,
1410            expressions,
1411            span,
1412        )?;
1413
1414        Ok(expressions.append(
1415            crate::Expression::Compose {
1416                ty: root_lookup.handle,
1417                components,
1418            },
1419            span,
1420        ))
1421    }
1422
1423    /// Return the Naga [`Expression`] for `pointer_id`, and its referent [`Type`].
1424    ///
1425    /// Return a [`Handle`] for a Naga [`Expression`] that holds the value of
1426    /// the SPIR-V instruction `pointer_id`, along with the [`Type`] to which it
1427    /// is a pointer.
1428    ///
1429    /// This may entail spilling `pointer_id`'s value to a temporary:
1430    /// see [`get_expr_handle`]'s documentation.
1431    ///
1432    /// [`Expression`]: crate::Expression
1433    /// [`Type`]: crate::Type
1434    /// [`Handle`]: crate::Handle
1435    /// [`get_expr_handle`]: Frontend::get_expr_handle
1436    fn get_exp_and_base_ty_handles(
1437        &self,
1438        pointer_id: spirv::Word,
1439        ctx: &mut BlockContext,
1440        emitter: &mut crate::proc::Emitter,
1441        block: &mut crate::Block,
1442        body_idx: usize,
1443    ) -> Result<(Handle<crate::Expression>, Handle<crate::Type>), Error> {
1444        log::trace!("\t\t\tlooking up pointer expr {pointer_id:?}");
1445        let p_lexp_handle;
1446        let p_lexp_ty_id;
1447        {
1448            let lexp = self.lookup_expression.lookup(pointer_id)?;
1449            p_lexp_handle = self.get_expr_handle(pointer_id, lexp, ctx, emitter, block, body_idx);
1450            p_lexp_ty_id = lexp.type_id;
1451        };
1452
1453        log::trace!("\t\t\tlooking up pointer type {pointer_id:?}");
1454        let p_ty = self.lookup_type.lookup(p_lexp_ty_id)?;
1455        let p_ty_base_id = p_ty.base_id.ok_or(Error::InvalidAccessType(p_lexp_ty_id))?;
1456
1457        log::trace!("\t\t\tlooking up pointer base type {p_ty_base_id:?} of {p_ty:?}");
1458        let p_base_ty = self.lookup_type.lookup(p_ty_base_id)?;
1459
1460        Ok((p_lexp_handle, p_base_ty.handle))
1461    }
1462
1463    #[allow(clippy::too_many_arguments)]
1464    fn parse_atomic_expr_with_value(
1465        &mut self,
1466        inst: Instruction,
1467        emitter: &mut crate::proc::Emitter,
1468        ctx: &mut BlockContext,
1469        block: &mut crate::Block,
1470        block_id: spirv::Word,
1471        body_idx: usize,
1472        atomic_function: crate::AtomicFunction,
1473    ) -> Result<(), Error> {
1474        inst.expect(7)?;
1475        let start = self.data_offset;
1476        let result_type_id = self.next()?;
1477        let result_id = self.next()?;
1478        let pointer_id = self.next()?;
1479        let _scope_id = self.next()?;
1480        let _memory_semantics_id = self.next()?;
1481        let value_id = self.next()?;
1482        let span = self.span_from_with_op(start);
1483
1484        let (p_lexp_handle, p_base_ty_handle) =
1485            self.get_exp_and_base_ty_handles(pointer_id, ctx, emitter, block, body_idx)?;
1486
1487        log::trace!("\t\t\tlooking up value expr {value_id:?}");
1488        let v_lexp_handle = self.lookup_expression.lookup(value_id)?.handle;
1489
1490        block.extend(emitter.finish(ctx.expressions));
1491        // Create an expression for our result
1492        let r_lexp_handle = {
1493            let expr = crate::Expression::AtomicResult {
1494                ty: p_base_ty_handle,
1495                comparison: false,
1496            };
1497            let handle = ctx.expressions.append(expr, span);
1498            self.lookup_expression.insert(
1499                result_id,
1500                LookupExpression {
1501                    handle,
1502                    type_id: result_type_id,
1503                    block_id,
1504                },
1505            );
1506            handle
1507        };
1508        emitter.start(ctx.expressions);
1509
1510        // Create a statement for the op itself
1511        let stmt = crate::Statement::Atomic {
1512            pointer: p_lexp_handle,
1513            fun: atomic_function,
1514            value: v_lexp_handle,
1515            result: Some(r_lexp_handle),
1516        };
1517        block.push(stmt, span);
1518
1519        // Store any associated global variables so we can upgrade their types later
1520        self.record_atomic_access(ctx, p_lexp_handle)?;
1521
1522        Ok(())
1523    }
1524
1525    fn make_expression_storage(
1526        &mut self,
1527        globals: &Arena<crate::GlobalVariable>,
1528        constants: &Arena<crate::Constant>,
1529        overrides: &Arena<crate::Override>,
1530    ) -> Arena<crate::Expression> {
1531        let mut expressions = Arena::new();
1532        assert!(self.lookup_expression.is_empty());
1533        // register global variables
1534        for (&id, var) in self.lookup_variable.iter() {
1535            let span = globals.get_span(var.handle);
1536            let handle = expressions.append(crate::Expression::GlobalVariable(var.handle), span);
1537            self.lookup_expression.insert(
1538                id,
1539                LookupExpression {
1540                    type_id: var.type_id,
1541                    handle,
1542                    // Setting this to an invalid id will cause get_expr_handle
1543                    // to default to the main body making sure no load/stores
1544                    // are added.
1545                    block_id: 0,
1546                },
1547            );
1548        }
1549        // register constants
1550        for (&id, con) in self.lookup_constant.iter() {
1551            let (expr, span) = match con.inner {
1552                Constant::Constant(c) => (crate::Expression::Constant(c), constants.get_span(c)),
1553                Constant::Override(o) => (crate::Expression::Override(o), overrides.get_span(o)),
1554            };
1555            let handle = expressions.append(expr, span);
1556            self.lookup_expression.insert(
1557                id,
1558                LookupExpression {
1559                    type_id: con.type_id,
1560                    handle,
1561                    // Setting this to an invalid id will cause get_expr_handle
1562                    // to default to the main body making sure no load/stores
1563                    // are added.
1564                    block_id: 0,
1565                },
1566            );
1567        }
1568        // done
1569        expressions
1570    }
1571
1572    fn switch(&mut self, state: ModuleState, op: spirv::Op) -> Result<(), Error> {
1573        if state < self.state {
1574            Err(Error::UnsupportedInstruction(self.state, op))
1575        } else {
1576            self.state = state;
1577            Ok(())
1578        }
1579    }
1580
1581    /// Walk the statement tree and patch it in the following cases:
1582    /// 1. Function call targets are replaced by `deferred_function_calls` map
1583    fn patch_statements(
1584        &mut self,
1585        statements: &mut crate::Block,
1586        expressions: &mut Arena<crate::Expression>,
1587        fun_parameter_sampling: &mut [image::SamplingFlags],
1588    ) -> Result<(), Error> {
1589        use crate::Statement as S;
1590        let mut i = 0usize;
1591        while i < statements.len() {
1592            match statements[i] {
1593                S::Emit(_) => {}
1594                S::Block(ref mut block) => {
1595                    self.patch_statements(block, expressions, fun_parameter_sampling)?;
1596                }
1597                S::If {
1598                    condition: _,
1599                    ref mut accept,
1600                    ref mut reject,
1601                } => {
1602                    self.patch_statements(reject, expressions, fun_parameter_sampling)?;
1603                    self.patch_statements(accept, expressions, fun_parameter_sampling)?;
1604                }
1605                S::Switch {
1606                    selector: _,
1607                    ref mut cases,
1608                } => {
1609                    for case in cases.iter_mut() {
1610                        self.patch_statements(&mut case.body, expressions, fun_parameter_sampling)?;
1611                    }
1612                }
1613                S::Loop {
1614                    ref mut body,
1615                    ref mut continuing,
1616                    break_if: _,
1617                } => {
1618                    self.patch_statements(body, expressions, fun_parameter_sampling)?;
1619                    self.patch_statements(continuing, expressions, fun_parameter_sampling)?;
1620                }
1621                S::Break
1622                | S::Continue
1623                | S::Return { .. }
1624                | S::Kill
1625                | S::ControlBarrier(_)
1626                | S::MemoryBarrier(_)
1627                | S::Store { .. }
1628                | S::ImageStore { .. }
1629                | S::Atomic { .. }
1630                | S::ImageAtomic { .. }
1631                | S::RayQuery { .. }
1632                | S::SubgroupBallot { .. }
1633                | S::SubgroupCollectiveOperation { .. }
1634                | S::SubgroupGather { .. }
1635                | S::RayPipelineFunction(..) => {}
1636                S::Call {
1637                    function: ref mut callee,
1638                    ref arguments,
1639                    ..
1640                } => {
1641                    let fun_id = self.deferred_function_calls[callee.index()];
1642                    let fun_lookup = self.lookup_function.lookup(fun_id)?;
1643                    *callee = fun_lookup.handle;
1644
1645                    // Patch sampling flags
1646                    for (arg_index, arg) in arguments.iter().enumerate() {
1647                        let flags = match fun_lookup.parameters_sampling.get(arg_index) {
1648                            Some(&flags) if !flags.is_empty() => flags,
1649                            _ => continue,
1650                        };
1651
1652                        match expressions[*arg] {
1653                            crate::Expression::GlobalVariable(handle) => {
1654                                if let Some(sampling) = self.handle_sampling.get_mut(&handle) {
1655                                    *sampling |= flags
1656                                }
1657                            }
1658                            crate::Expression::FunctionArgument(i) => {
1659                                fun_parameter_sampling[i as usize] |= flags;
1660                            }
1661                            ref other => return Err(Error::InvalidGlobalVar(other.clone())),
1662                        }
1663                    }
1664                }
1665                S::WorkGroupUniformLoad { .. } => unreachable!(),
1666                S::CooperativeStore { .. } => unreachable!(),
1667            }
1668            i += 1;
1669        }
1670        Ok(())
1671    }
1672
1673    fn patch_function(
1674        &mut self,
1675        handle: Option<Handle<crate::Function>>,
1676        fun: &mut crate::Function,
1677    ) -> Result<(), Error> {
1678        // Note: this search is a bit unfortunate
1679        let (fun_id, mut parameters_sampling) = match handle {
1680            Some(h) => {
1681                let (&fun_id, lookup) = self
1682                    .lookup_function
1683                    .iter_mut()
1684                    .find(|&(_, ref lookup)| lookup.handle == h)
1685                    .unwrap();
1686                (fun_id, mem::take(&mut lookup.parameters_sampling))
1687            }
1688            None => (0, Vec::new()),
1689        };
1690
1691        for (_, expr) in fun.expressions.iter_mut() {
1692            if let crate::Expression::CallResult(ref mut function) = *expr {
1693                let fun_id = self.deferred_function_calls[function.index()];
1694                *function = self.lookup_function.lookup(fun_id)?.handle;
1695            }
1696        }
1697
1698        self.patch_statements(
1699            &mut fun.body,
1700            &mut fun.expressions,
1701            &mut parameters_sampling,
1702        )?;
1703
1704        if let Some(lookup) = self.lookup_function.get_mut(&fun_id) {
1705            lookup.parameters_sampling = parameters_sampling;
1706        }
1707        Ok(())
1708    }
1709
1710    pub fn parse(mut self) -> Result<crate::Module, Error> {
1711        let mut module = {
1712            if self.next()? != spirv::MAGIC_NUMBER {
1713                return Err(Error::InvalidHeader);
1714            }
1715            let version_raw = self.next()?;
1716            let generator = self.next()?;
1717            let _bound = self.next()?;
1718            let _schema = self.next()?;
1719            log::debug!("Generated by {generator} version {version_raw:x}");
1720            crate::Module::default()
1721        };
1722
1723        self.layouter.clear();
1724        self.dummy_functions = Arena::new();
1725        self.lookup_function.clear();
1726        self.function_call_graph.clear();
1727
1728        loop {
1729            use spirv::Op;
1730
1731            let inst = match self.next_inst() {
1732                Ok(inst) => inst,
1733                Err(Error::IncompleteData) => break,
1734                Err(other) => return Err(other),
1735            };
1736            log::debug!("\t{:?} [{}]", inst.op, inst.wc);
1737
1738            match inst.op {
1739                Op::Capability => self.parse_capability(inst),
1740                Op::Extension => self.parse_extension(inst),
1741                Op::ExtInstImport => self.parse_ext_inst_import(inst),
1742                Op::MemoryModel => self.parse_memory_model(inst),
1743                Op::EntryPoint => self.parse_entry_point(inst),
1744                Op::ExecutionMode => self.parse_execution_mode(inst),
1745                Op::String => self.parse_string(inst),
1746                Op::Source => self.parse_source(inst),
1747                Op::SourceExtension => self.parse_source_extension(inst),
1748                Op::Name => self.parse_name(inst),
1749                Op::MemberName => self.parse_member_name(inst),
1750                Op::ModuleProcessed => self.parse_module_processed(inst),
1751                Op::Decorate => self.parse_decorate(inst),
1752                Op::MemberDecorate => self.parse_member_decorate(inst),
1753                Op::TypeVoid => self.parse_type_void(inst),
1754                Op::TypeBool => self.parse_type_bool(inst, &mut module),
1755                Op::TypeInt => self.parse_type_int(inst, &mut module),
1756                Op::TypeFloat => self.parse_type_float(inst, &mut module),
1757                Op::TypeVector => self.parse_type_vector(inst, &mut module),
1758                Op::TypeMatrix => self.parse_type_matrix(inst, &mut module),
1759                Op::TypeFunction => self.parse_type_function(inst),
1760                Op::TypePointer => self.parse_type_pointer(inst, &mut module),
1761                Op::TypeArray => self.parse_type_array(inst, &mut module),
1762                Op::TypeRuntimeArray => self.parse_type_runtime_array(inst, &mut module),
1763                Op::TypeStruct => self.parse_type_struct(inst, &mut module),
1764                Op::TypeImage => self.parse_type_image(inst, &mut module),
1765                Op::TypeSampledImage => self.parse_type_sampled_image(inst),
1766                Op::TypeSampler => self.parse_type_sampler(inst, &mut module),
1767                Op::Constant | Op::SpecConstant => self.parse_constant(inst, &mut module),
1768                Op::ConstantComposite | Op::SpecConstantComposite => {
1769                    self.parse_composite_constant(inst, &mut module)
1770                }
1771                Op::ConstantNull | Op::Undef => self.parse_null_constant(inst, &mut module),
1772                Op::ConstantTrue | Op::SpecConstantTrue => {
1773                    self.parse_bool_constant(inst, true, &mut module)
1774                }
1775                Op::ConstantFalse | Op::SpecConstantFalse => {
1776                    self.parse_bool_constant(inst, false, &mut module)
1777                }
1778                Op::Variable => self.parse_global_variable(inst, &mut module),
1779                Op::Function => {
1780                    self.switch(ModuleState::Function, inst.op)?;
1781                    inst.expect(5)?;
1782                    self.parse_function(&mut module)
1783                }
1784                Op::ExtInst => {
1785                    // Ignore the result type and result id
1786                    let _ = self.next()?;
1787                    let _ = self.next()?;
1788                    let set_id = self.next()?;
1789                    if Some(set_id) == self.ext_non_semantic_id {
1790                        // We've already skipped the instruction byte, result type, result id, and instruction set id
1791                        for _ in 0..inst.wc - 4 {
1792                            self.next()?;
1793                        }
1794                        Ok(())
1795                    } else {
1796                        return Err(Error::UnsupportedInstruction(self.state, inst.op));
1797                    }
1798                }
1799                _ => Err(Error::UnsupportedInstruction(self.state, inst.op)), //TODO
1800            }?;
1801        }
1802
1803        if !self.upgrade_atomics.is_empty() {
1804            log::debug!("Upgrading atomic pointers...");
1805            module.upgrade_atomics(&self.upgrade_atomics)?;
1806        }
1807
1808        // Do entry point specific processing after all functions are parsed so that we can
1809        // cull unused problematic builtins of gl_PerVertex.
1810        for (ep, fun_id) in mem::take(&mut self.deferred_entry_points) {
1811            self.process_entry_point(&mut module, ep, fun_id)?;
1812        }
1813
1814        log::debug!("Patching...");
1815        {
1816            let mut nodes = petgraph::algo::toposort(&self.function_call_graph, None)
1817                .map_err(|cycle| Error::FunctionCallCycle(cycle.node_id()))?;
1818            nodes.reverse(); // we need dominated first
1819            let mut functions = mem::take(&mut module.functions);
1820            for fun_id in nodes {
1821                if fun_id > !(functions.len() as u32) {
1822                    // skip all the fake IDs registered for the entry points
1823                    continue;
1824                }
1825                let lookup = self.lookup_function.get_mut(&fun_id).unwrap();
1826                // take out the function from the old array
1827                let fun = mem::take(&mut functions[lookup.handle]);
1828                // add it to the newly formed arena, and adjust the lookup
1829                lookup.handle = module
1830                    .functions
1831                    .append(fun, functions.get_span(lookup.handle));
1832            }
1833        }
1834        // patch all the functions
1835        for (handle, fun) in module.functions.iter_mut() {
1836            self.patch_function(Some(handle), fun)?;
1837        }
1838        for ep in module.entry_points.iter_mut() {
1839            self.patch_function(None, &mut ep.function)?;
1840        }
1841
1842        // Check all the images and samplers to have consistent comparison property.
1843        for (handle, flags) in self.handle_sampling.drain() {
1844            if !image::patch_comparison_type(
1845                flags,
1846                module.global_variables.get_mut(handle),
1847                &mut module.types,
1848            ) {
1849                return Err(Error::InconsistentComparisonSampling(handle));
1850            }
1851        }
1852
1853        if !self.future_decor.is_empty() {
1854            log::debug!("Unused item decorations: {:?}", self.future_decor);
1855            self.future_decor.clear();
1856        }
1857        if !self.future_member_decor.is_empty() {
1858            log::debug!("Unused member decorations: {:?}", self.future_member_decor);
1859            self.future_member_decor.clear();
1860        }
1861
1862        Ok(module)
1863    }
1864
1865    fn parse_capability(&mut self, inst: Instruction) -> Result<(), Error> {
1866        self.switch(ModuleState::Capability, inst.op)?;
1867        inst.expect(2)?;
1868        let capability = self.next()?;
1869        let cap =
1870            spirv::Capability::from_u32(capability).ok_or(Error::UnknownCapability(capability))?;
1871        if !SUPPORTED_CAPABILITIES.contains(&cap) {
1872            if self.options.strict_capabilities {
1873                return Err(Error::UnsupportedCapability(cap));
1874            } else {
1875                log::warn!("Unknown capability {cap:?}");
1876            }
1877        }
1878        Ok(())
1879    }
1880
1881    fn parse_extension(&mut self, inst: Instruction) -> Result<(), Error> {
1882        self.switch(ModuleState::Extension, inst.op)?;
1883        inst.expect_at_least(2)?;
1884        let (name, left) = self.next_string(inst.wc - 1)?;
1885        if left != 0 {
1886            return Err(Error::InvalidOperand);
1887        }
1888        if !SUPPORTED_EXTENSIONS.contains(&name.as_str()) {
1889            return Err(Error::UnsupportedExtension(name));
1890        }
1891        Ok(())
1892    }
1893
1894    fn parse_ext_inst_import(&mut self, inst: Instruction) -> Result<(), Error> {
1895        self.switch(ModuleState::Extension, inst.op)?;
1896        inst.expect_at_least(3)?;
1897        let result_id = self.next()?;
1898        let (name, left) = self.next_string(inst.wc - 2)?;
1899        if left != 0 {
1900            return Err(Error::InvalidOperand);
1901        }
1902        if &name == "GLSL.std.450" {
1903            self.ext_glsl_id = Some(result_id);
1904        } else if &name == "NonSemantic.Shader.DebugInfo.100" {
1905            // We completely ignore this extension. All related instructions are
1906            // non-semantic and only for debug purposes, and the spec says they
1907            // are ignorable. Many compilers (dxc, slang, etc) will emit these
1908            // instructions depending on configuration.
1909            self.ext_non_semantic_id = Some(result_id);
1910        } else {
1911            return Err(Error::UnsupportedExtSet(name));
1912        }
1913        Ok(())
1914    }
1915
1916    fn parse_memory_model(&mut self, inst: Instruction) -> Result<(), Error> {
1917        self.switch(ModuleState::MemoryModel, inst.op)?;
1918        inst.expect(3)?;
1919        let _addressing_model = self.next()?;
1920        let _memory_model = self.next()?;
1921        Ok(())
1922    }
1923
1924    fn parse_entry_point(&mut self, inst: Instruction) -> Result<(), Error> {
1925        self.switch(ModuleState::EntryPoint, inst.op)?;
1926        inst.expect_at_least(4)?;
1927        let exec_model = self.next()?;
1928        let exec_model = spirv::ExecutionModel::from_u32(exec_model)
1929            .ok_or(Error::UnsupportedExecutionModel(exec_model))?;
1930        let function_id = self.next()?;
1931        let (name, left) = self.next_string(inst.wc - 3)?;
1932        let ep = EntryPoint {
1933            stage: match exec_model {
1934                spirv::ExecutionModel::Vertex => crate::ShaderStage::Vertex,
1935                spirv::ExecutionModel::Fragment => crate::ShaderStage::Fragment,
1936                spirv::ExecutionModel::GLCompute => crate::ShaderStage::Compute,
1937                spirv::ExecutionModel::TaskEXT => crate::ShaderStage::Task,
1938                spirv::ExecutionModel::MeshEXT => crate::ShaderStage::Mesh,
1939                _ => return Err(Error::UnsupportedExecutionModel(exec_model as u32)),
1940            },
1941            name,
1942            early_depth_test: None,
1943            workgroup_size: [0; 3],
1944            variable_ids: self.data.by_ref().take(left as usize).collect(),
1945        };
1946        self.lookup_entry_point.insert(function_id, ep);
1947        Ok(())
1948    }
1949
1950    fn parse_execution_mode(&mut self, inst: Instruction) -> Result<(), Error> {
1951        use spirv::ExecutionMode;
1952
1953        self.switch(ModuleState::ExecutionMode, inst.op)?;
1954        inst.expect_at_least(3)?;
1955
1956        let ep_id = self.next()?;
1957        let mode_id = self.next()?;
1958        let args: Vec<spirv::Word> = self.data.by_ref().take(inst.wc as usize - 3).collect();
1959
1960        let ep = self
1961            .lookup_entry_point
1962            .get_mut(&ep_id)
1963            .ok_or(Error::InvalidId(ep_id))?;
1964        let mode =
1965            ExecutionMode::from_u32(mode_id).ok_or(Error::UnsupportedExecutionMode(mode_id))?;
1966
1967        match mode {
1968            ExecutionMode::EarlyFragmentTests => {
1969                ep.early_depth_test = Some(crate::EarlyDepthTest::Force);
1970            }
1971            ExecutionMode::DepthUnchanged => {
1972                if let &mut Some(ref mut early_depth_test) = &mut ep.early_depth_test {
1973                    if let &mut crate::EarlyDepthTest::Allow {
1974                        ref mut conservative,
1975                    } = early_depth_test
1976                    {
1977                        *conservative = crate::ConservativeDepth::Unchanged;
1978                    }
1979                } else {
1980                    ep.early_depth_test = Some(crate::EarlyDepthTest::Allow {
1981                        conservative: crate::ConservativeDepth::Unchanged,
1982                    });
1983                }
1984            }
1985            ExecutionMode::DepthGreater => {
1986                if let &mut Some(ref mut early_depth_test) = &mut ep.early_depth_test {
1987                    if let &mut crate::EarlyDepthTest::Allow {
1988                        ref mut conservative,
1989                    } = early_depth_test
1990                    {
1991                        *conservative = crate::ConservativeDepth::GreaterEqual;
1992                    }
1993                } else {
1994                    ep.early_depth_test = Some(crate::EarlyDepthTest::Allow {
1995                        conservative: crate::ConservativeDepth::GreaterEqual,
1996                    });
1997                }
1998            }
1999            ExecutionMode::DepthLess => {
2000                if let &mut Some(ref mut early_depth_test) = &mut ep.early_depth_test {
2001                    if let &mut crate::EarlyDepthTest::Allow {
2002                        ref mut conservative,
2003                    } = early_depth_test
2004                    {
2005                        *conservative = crate::ConservativeDepth::LessEqual;
2006                    }
2007                } else {
2008                    ep.early_depth_test = Some(crate::EarlyDepthTest::Allow {
2009                        conservative: crate::ConservativeDepth::LessEqual,
2010                    });
2011                }
2012            }
2013            ExecutionMode::DepthReplacing => {
2014                // Ignored because it can be deduced from the IR.
2015            }
2016            ExecutionMode::OriginUpperLeft => {
2017                // Ignored because the other option (OriginLowerLeft) is not valid in Vulkan mode.
2018            }
2019            ExecutionMode::LocalSize => {
2020                ep.workgroup_size = [args[0], args[1], args[2]];
2021            }
2022            _ => {
2023                return Err(Error::UnsupportedExecutionMode(mode_id));
2024            }
2025        }
2026
2027        Ok(())
2028    }
2029
2030    fn parse_string(&mut self, inst: Instruction) -> Result<(), Error> {
2031        self.switch(ModuleState::Source, inst.op)?;
2032        inst.expect_at_least(3)?;
2033        let _id = self.next()?;
2034        let (_name, _) = self.next_string(inst.wc - 2)?;
2035        Ok(())
2036    }
2037
2038    fn parse_source(&mut self, inst: Instruction) -> Result<(), Error> {
2039        self.switch(ModuleState::Source, inst.op)?;
2040        for _ in 1..inst.wc {
2041            let _ = self.next()?;
2042        }
2043        Ok(())
2044    }
2045
2046    fn parse_source_extension(&mut self, inst: Instruction) -> Result<(), Error> {
2047        self.switch(ModuleState::Source, inst.op)?;
2048        inst.expect_at_least(2)?;
2049        let (_name, _) = self.next_string(inst.wc - 1)?;
2050        Ok(())
2051    }
2052
2053    fn parse_name(&mut self, inst: Instruction) -> Result<(), Error> {
2054        self.switch(ModuleState::Name, inst.op)?;
2055        inst.expect_at_least(3)?;
2056        let id = self.next()?;
2057        let (name, left) = self.next_string(inst.wc - 2)?;
2058        if left != 0 {
2059            return Err(Error::InvalidOperand);
2060        }
2061        self.future_decor.entry(id).or_default().name = Some(name);
2062        Ok(())
2063    }
2064
2065    fn parse_member_name(&mut self, inst: Instruction) -> Result<(), Error> {
2066        self.switch(ModuleState::Name, inst.op)?;
2067        inst.expect_at_least(4)?;
2068        let id = self.next()?;
2069        let member = self.next()?;
2070        let (name, left) = self.next_string(inst.wc - 3)?;
2071        if left != 0 {
2072            return Err(Error::InvalidOperand);
2073        }
2074
2075        self.future_member_decor
2076            .entry((id, member))
2077            .or_default()
2078            .name = Some(name);
2079        Ok(())
2080    }
2081
2082    fn parse_module_processed(&mut self, inst: Instruction) -> Result<(), Error> {
2083        self.switch(ModuleState::Name, inst.op)?;
2084        inst.expect_at_least(2)?;
2085        let (_info, left) = self.next_string(inst.wc - 1)?;
2086        //Note: string is ignored
2087        if left != 0 {
2088            return Err(Error::InvalidOperand);
2089        }
2090        Ok(())
2091    }
2092
2093    fn parse_decorate(&mut self, inst: Instruction) -> Result<(), Error> {
2094        self.switch(ModuleState::Annotation, inst.op)?;
2095        inst.expect_at_least(3)?;
2096        let id = self.next()?;
2097        let mut dec = self.future_decor.remove(&id).unwrap_or_default();
2098        self.next_decoration(inst, 2, &mut dec)?;
2099        self.future_decor.insert(id, dec);
2100        Ok(())
2101    }
2102
2103    fn parse_member_decorate(&mut self, inst: Instruction) -> Result<(), Error> {
2104        self.switch(ModuleState::Annotation, inst.op)?;
2105        inst.expect_at_least(4)?;
2106        let id = self.next()?;
2107        let member = self.next()?;
2108
2109        let mut dec = self
2110            .future_member_decor
2111            .remove(&(id, member))
2112            .unwrap_or_default();
2113        self.next_decoration(inst, 3, &mut dec)?;
2114        self.future_member_decor.insert((id, member), dec);
2115        Ok(())
2116    }
2117
2118    fn parse_type_void(&mut self, inst: Instruction) -> Result<(), Error> {
2119        self.switch(ModuleState::Type, inst.op)?;
2120        inst.expect(2)?;
2121        let id = self.next()?;
2122        self.lookup_void_type = Some(id);
2123        Ok(())
2124    }
2125
2126    fn parse_type_bool(
2127        &mut self,
2128        inst: Instruction,
2129        module: &mut crate::Module,
2130    ) -> Result<(), Error> {
2131        let start = self.data_offset;
2132        self.switch(ModuleState::Type, inst.op)?;
2133        inst.expect(2)?;
2134        let id = self.next()?;
2135        let inner = crate::TypeInner::Scalar(crate::Scalar::BOOL);
2136        self.lookup_type.insert(
2137            id,
2138            LookupType {
2139                handle: module.types.insert(
2140                    crate::Type {
2141                        name: self.future_decor.remove(&id).and_then(|dec| dec.name),
2142                        inner,
2143                    },
2144                    self.span_from_with_op(start),
2145                ),
2146                base_id: None,
2147            },
2148        );
2149        Ok(())
2150    }
2151
2152    fn parse_type_int(
2153        &mut self,
2154        inst: Instruction,
2155        module: &mut crate::Module,
2156    ) -> Result<(), Error> {
2157        let start = self.data_offset;
2158        self.switch(ModuleState::Type, inst.op)?;
2159        inst.expect(4)?;
2160        let id = self.next()?;
2161        let width = self.next()?;
2162        let sign = self.next()?;
2163        let inner = crate::TypeInner::Scalar(crate::Scalar {
2164            kind: match sign {
2165                0 => crate::ScalarKind::Uint,
2166                1 => crate::ScalarKind::Sint,
2167                _ => return Err(Error::InvalidSign(sign)),
2168            },
2169            width: map_width(width)?,
2170        });
2171        self.lookup_type.insert(
2172            id,
2173            LookupType {
2174                handle: module.types.insert(
2175                    crate::Type {
2176                        name: self.future_decor.remove(&id).and_then(|dec| dec.name),
2177                        inner,
2178                    },
2179                    self.span_from_with_op(start),
2180                ),
2181                base_id: None,
2182            },
2183        );
2184        Ok(())
2185    }
2186
2187    fn parse_type_float(
2188        &mut self,
2189        inst: Instruction,
2190        module: &mut crate::Module,
2191    ) -> Result<(), Error> {
2192        let start = self.data_offset;
2193        self.switch(ModuleState::Type, inst.op)?;
2194        inst.expect(3)?;
2195        let id = self.next()?;
2196        let width = self.next()?;
2197        let inner = crate::TypeInner::Scalar(crate::Scalar::float(map_width(width)?));
2198        self.lookup_type.insert(
2199            id,
2200            LookupType {
2201                handle: module.types.insert(
2202                    crate::Type {
2203                        name: self.future_decor.remove(&id).and_then(|dec| dec.name),
2204                        inner,
2205                    },
2206                    self.span_from_with_op(start),
2207                ),
2208                base_id: None,
2209            },
2210        );
2211        Ok(())
2212    }
2213
2214    fn parse_type_vector(
2215        &mut self,
2216        inst: Instruction,
2217        module: &mut crate::Module,
2218    ) -> Result<(), Error> {
2219        let start = self.data_offset;
2220        self.switch(ModuleState::Type, inst.op)?;
2221        inst.expect(4)?;
2222        let id = self.next()?;
2223        let type_id = self.next()?;
2224        let type_lookup = self.lookup_type.lookup(type_id)?;
2225        let scalar = match module.types[type_lookup.handle].inner {
2226            crate::TypeInner::Scalar(scalar) => scalar,
2227            _ => return Err(Error::InvalidInnerType(type_id)),
2228        };
2229        let component_count = self.next()?;
2230        let inner = crate::TypeInner::Vector {
2231            size: map_vector_size(component_count)?,
2232            scalar,
2233        };
2234        self.lookup_type.insert(
2235            id,
2236            LookupType {
2237                handle: module.types.insert(
2238                    crate::Type {
2239                        name: self.future_decor.remove(&id).and_then(|dec| dec.name),
2240                        inner,
2241                    },
2242                    self.span_from_with_op(start),
2243                ),
2244                base_id: Some(type_id),
2245            },
2246        );
2247        Ok(())
2248    }
2249
2250    fn parse_type_matrix(
2251        &mut self,
2252        inst: Instruction,
2253        module: &mut crate::Module,
2254    ) -> Result<(), Error> {
2255        let start = self.data_offset;
2256        self.switch(ModuleState::Type, inst.op)?;
2257        inst.expect(4)?;
2258        let id = self.next()?;
2259        let vector_type_id = self.next()?;
2260        let num_columns = self.next()?;
2261        let decor = self.future_decor.remove(&id);
2262
2263        let vector_type_lookup = self.lookup_type.lookup(vector_type_id)?;
2264        let inner = match module.types[vector_type_lookup.handle].inner {
2265            crate::TypeInner::Vector { size, scalar } => crate::TypeInner::Matrix {
2266                columns: map_vector_size(num_columns)?,
2267                rows: size,
2268                scalar,
2269            },
2270            _ => return Err(Error::InvalidInnerType(vector_type_id)),
2271        };
2272
2273        self.lookup_type.insert(
2274            id,
2275            LookupType {
2276                handle: module.types.insert(
2277                    crate::Type {
2278                        name: decor.and_then(|dec| dec.name),
2279                        inner,
2280                    },
2281                    self.span_from_with_op(start),
2282                ),
2283                base_id: Some(vector_type_id),
2284            },
2285        );
2286        Ok(())
2287    }
2288
2289    fn parse_type_function(&mut self, inst: Instruction) -> Result<(), Error> {
2290        self.switch(ModuleState::Type, inst.op)?;
2291        inst.expect_at_least(3)?;
2292        let id = self.next()?;
2293        let return_type_id = self.next()?;
2294        let parameter_type_ids = self.data.by_ref().take(inst.wc as usize - 3).collect();
2295        self.lookup_function_type.insert(
2296            id,
2297            LookupFunctionType {
2298                parameter_type_ids,
2299                return_type_id,
2300            },
2301        );
2302        Ok(())
2303    }
2304
2305    fn parse_type_pointer(
2306        &mut self,
2307        inst: Instruction,
2308        module: &mut crate::Module,
2309    ) -> Result<(), Error> {
2310        let start = self.data_offset;
2311        self.switch(ModuleState::Type, inst.op)?;
2312        inst.expect(4)?;
2313        let id = self.next()?;
2314        let storage_class = self.next()?;
2315        let type_id = self.next()?;
2316
2317        let decor = self.future_decor.remove(&id);
2318        let base_lookup_ty = self.lookup_type.lookup(type_id)?;
2319        let base_inner = &module.types[base_lookup_ty.handle].inner;
2320
2321        let space = if let Some(space) = base_inner.pointer_space() {
2322            space
2323        } else if self
2324            .lookup_storage_buffer_types
2325            .contains_key(&base_lookup_ty.handle)
2326        {
2327            crate::AddressSpace::Storage {
2328                access: crate::StorageAccess::default(),
2329            }
2330        } else {
2331            match map_storage_class(storage_class)? {
2332                ExtendedClass::Global(space) => space,
2333                ExtendedClass::Input | ExtendedClass::Output => crate::AddressSpace::Private,
2334            }
2335        };
2336
2337        // We don't support pointers to runtime-sized arrays in the `Uniform`
2338        // storage class with the `BufferBlock` decoration. Runtime-sized arrays
2339        // should be in the StorageBuffer class.
2340        if let crate::TypeInner::Array {
2341            size: crate::ArraySize::Dynamic,
2342            ..
2343        } = *base_inner
2344        {
2345            match space {
2346                crate::AddressSpace::Storage { .. } => {}
2347                _ => {
2348                    return Err(Error::UnsupportedRuntimeArrayStorageClass);
2349                }
2350            }
2351        }
2352
2353        // Don't bother with pointer stuff for `Handle` types.
2354        let lookup_ty = if space == crate::AddressSpace::Handle {
2355            base_lookup_ty.clone()
2356        } else {
2357            LookupType {
2358                handle: module.types.insert(
2359                    crate::Type {
2360                        name: decor.and_then(|dec| dec.name),
2361                        inner: crate::TypeInner::Pointer {
2362                            base: base_lookup_ty.handle,
2363                            space,
2364                        },
2365                    },
2366                    self.span_from_with_op(start),
2367                ),
2368                base_id: Some(type_id),
2369            }
2370        };
2371        self.lookup_type.insert(id, lookup_ty);
2372        Ok(())
2373    }
2374
2375    fn parse_type_array(
2376        &mut self,
2377        inst: Instruction,
2378        module: &mut crate::Module,
2379    ) -> Result<(), Error> {
2380        let start = self.data_offset;
2381        self.switch(ModuleState::Type, inst.op)?;
2382        inst.expect(4)?;
2383        let id = self.next()?;
2384        let type_id = self.next()?;
2385        let length_id = self.next()?;
2386        let length_const = self.lookup_constant.lookup(length_id)?;
2387
2388        let size = resolve_constant(module.to_ctx(), &length_const.inner)
2389            .and_then(NonZeroU32::new)
2390            .ok_or(Error::InvalidArraySize(length_id))?;
2391
2392        let decor = self.future_decor.remove(&id).unwrap_or_default();
2393        let base = self.lookup_type.lookup(type_id)?.handle;
2394
2395        self.layouter.update(module.to_ctx()).unwrap();
2396
2397        // HACK if the underlying type is an image or a sampler, let's assume
2398        //      that we're dealing with a binding-array
2399        //
2400        // Note that it's not a strictly correct assumption, but rather a trade
2401        // off caused by an impedance mismatch between SPIR-V's and Naga's type
2402        // systems - Naga distinguishes between arrays and binding-arrays via
2403        // types (i.e. both kinds of arrays are just different types), while
2404        // SPIR-V distinguishes between them through usage - e.g. given:
2405        //
2406        // ```
2407        // %image = OpTypeImage %float 2D 2 0 0 2 Rgba16f
2408        // %uint_256 = OpConstant %uint 256
2409        // %image_array = OpTypeArray %image %uint_256
2410        // ```
2411        //
2412        // ```
2413        // %image = OpTypeImage %float 2D 2 0 0 2 Rgba16f
2414        // %uint_256 = OpConstant %uint 256
2415        // %image_array = OpTypeArray %image %uint_256
2416        // %image_array_ptr = OpTypePointer UniformConstant %image_array
2417        // ```
2418        //
2419        // ... in the first case, `%image_array` should technically correspond
2420        // to `TypeInner::Array`, while in the second case it should say
2421        // `TypeInner::BindingArray` (kinda, depending on whether `%image_array`
2422        // is ever used as a freestanding type or rather always through the
2423        // pointer-indirection).
2424        //
2425        // Anyway, at the moment we don't support other kinds of image / sampler
2426        // arrays than those binding-based, so this assumption is pretty safe
2427        // for now.
2428        let inner = if let crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } =
2429            module.types[base].inner
2430        {
2431            crate::TypeInner::BindingArray {
2432                base,
2433                size: crate::ArraySize::Constant(size),
2434            }
2435        } else {
2436            crate::TypeInner::Array {
2437                base,
2438                size: crate::ArraySize::Constant(size),
2439                stride: match decor.array_stride {
2440                    Some(stride) => stride.get(),
2441                    None => self.layouter[base].to_stride(),
2442                },
2443            }
2444        };
2445
2446        self.lookup_type.insert(
2447            id,
2448            LookupType {
2449                handle: module.types.insert(
2450                    crate::Type {
2451                        name: decor.name,
2452                        inner,
2453                    },
2454                    self.span_from_with_op(start),
2455                ),
2456                base_id: Some(type_id),
2457            },
2458        );
2459        Ok(())
2460    }
2461
2462    fn parse_type_runtime_array(
2463        &mut self,
2464        inst: Instruction,
2465        module: &mut crate::Module,
2466    ) -> Result<(), Error> {
2467        let start = self.data_offset;
2468        self.switch(ModuleState::Type, inst.op)?;
2469        inst.expect(3)?;
2470        let id = self.next()?;
2471        let type_id = self.next()?;
2472
2473        let decor = self.future_decor.remove(&id).unwrap_or_default();
2474        let base = self.lookup_type.lookup(type_id)?.handle;
2475
2476        self.layouter.update(module.to_ctx()).unwrap();
2477
2478        // HACK same case as in `parse_type_array()`
2479        let inner = if let crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } =
2480            module.types[base].inner
2481        {
2482            crate::TypeInner::BindingArray {
2483                base: self.lookup_type.lookup(type_id)?.handle,
2484                size: crate::ArraySize::Dynamic,
2485            }
2486        } else {
2487            crate::TypeInner::Array {
2488                base: self.lookup_type.lookup(type_id)?.handle,
2489                size: crate::ArraySize::Dynamic,
2490                stride: match decor.array_stride {
2491                    Some(stride) => stride.get(),
2492                    None => self.layouter[base].to_stride(),
2493                },
2494            }
2495        };
2496
2497        self.lookup_type.insert(
2498            id,
2499            LookupType {
2500                handle: module.types.insert(
2501                    crate::Type {
2502                        name: decor.name,
2503                        inner,
2504                    },
2505                    self.span_from_with_op(start),
2506                ),
2507                base_id: Some(type_id),
2508            },
2509        );
2510        Ok(())
2511    }
2512
2513    fn parse_type_struct(
2514        &mut self,
2515        inst: Instruction,
2516        module: &mut crate::Module,
2517    ) -> Result<(), Error> {
2518        let start = self.data_offset;
2519        self.switch(ModuleState::Type, inst.op)?;
2520        inst.expect_at_least(2)?;
2521        let id = self.next()?;
2522        let parent_decor = self.future_decor.remove(&id);
2523        let is_storage_buffer = parent_decor
2524            .as_ref()
2525            .is_some_and(|decor| decor.storage_buffer);
2526
2527        self.layouter.update(module.to_ctx()).unwrap();
2528
2529        let mut members = Vec::<crate::StructMember>::with_capacity(inst.wc as usize - 2);
2530        let mut member_lookups = Vec::with_capacity(members.capacity());
2531        let mut storage_access = crate::StorageAccess::empty();
2532        let mut span = 0;
2533        let mut alignment = Alignment::ONE;
2534        for i in 0..u32::from(inst.wc) - 2 {
2535            let type_id = self.next()?;
2536            let ty = self.lookup_type.lookup(type_id)?.handle;
2537            let decor = self
2538                .future_member_decor
2539                .remove(&(id, i))
2540                .unwrap_or_default();
2541
2542            storage_access |= decor.flags.to_storage_access();
2543
2544            member_lookups.push(LookupMember {
2545                type_id,
2546                row_major: decor.matrix_major == Some(Majority::Row),
2547            });
2548
2549            let member_alignment = self.layouter[ty].alignment;
2550            span = member_alignment.round_up(span);
2551            alignment = member_alignment.max(alignment);
2552
2553            let binding = decor.io_binding().ok();
2554            if let Some(offset) = decor.offset {
2555                span = offset;
2556            }
2557            let offset = span;
2558
2559            span += self.layouter[ty].size;
2560
2561            let inner = &module.types[ty].inner;
2562            if let crate::TypeInner::Matrix {
2563                columns,
2564                rows,
2565                scalar,
2566            } = *inner
2567            {
2568                if let Some(stride) = decor.matrix_stride {
2569                    let expected_stride = Alignment::from(rows) * scalar.width as u32;
2570                    if stride.get() != expected_stride {
2571                        return Err(Error::UnsupportedMatrixStride {
2572                            stride: stride.get(),
2573                            columns: columns as u8,
2574                            rows: rows as u8,
2575                            width: scalar.width,
2576                        });
2577                    }
2578                }
2579            }
2580
2581            members.push(crate::StructMember {
2582                name: decor.name,
2583                ty,
2584                binding,
2585                offset,
2586            });
2587        }
2588
2589        span = alignment.round_up(span);
2590
2591        let inner = crate::TypeInner::Struct { span, members };
2592
2593        let ty_handle = module.types.insert(
2594            crate::Type {
2595                name: parent_decor.and_then(|dec| dec.name),
2596                inner,
2597            },
2598            self.span_from_with_op(start),
2599        );
2600
2601        if is_storage_buffer {
2602            self.lookup_storage_buffer_types
2603                .insert(ty_handle, storage_access);
2604        }
2605        for (i, member_lookup) in member_lookups.into_iter().enumerate() {
2606            self.lookup_member
2607                .insert((ty_handle, i as u32), member_lookup);
2608        }
2609        self.lookup_type.insert(
2610            id,
2611            LookupType {
2612                handle: ty_handle,
2613                base_id: None,
2614            },
2615        );
2616        Ok(())
2617    }
2618
2619    fn parse_type_image(
2620        &mut self,
2621        inst: Instruction,
2622        module: &mut crate::Module,
2623    ) -> Result<(), Error> {
2624        let start = self.data_offset;
2625        self.switch(ModuleState::Type, inst.op)?;
2626        inst.expect(9)?;
2627
2628        let id = self.next()?;
2629        let sample_type_id = self.next()?;
2630        let dim = self.next()?;
2631        let is_depth = self.next()?;
2632        let is_array = self.next()? != 0;
2633        let is_msaa = self.next()? != 0;
2634        let is_sampled = self.next()?;
2635        let format = self.next()?;
2636
2637        let dim = map_image_dim(dim)?;
2638        let decor = self.future_decor.remove(&id).unwrap_or_default();
2639
2640        // ensure there is a type for texture coordinate without extra components
2641        module.types.insert(
2642            crate::Type {
2643                name: None,
2644                inner: {
2645                    let scalar = crate::Scalar::F32;
2646                    match dim.required_coordinate_size() {
2647                        None => crate::TypeInner::Scalar(scalar),
2648                        Some(size) => crate::TypeInner::Vector { size, scalar },
2649                    }
2650                },
2651            },
2652            Default::default(),
2653        );
2654
2655        let base_handle = self.lookup_type.lookup(sample_type_id)?.handle;
2656        let kind = module.types[base_handle]
2657            .inner
2658            .scalar_kind()
2659            .ok_or(Error::InvalidImageBaseType(base_handle))?;
2660
2661        let inner = crate::TypeInner::Image {
2662            class: if is_depth == 1 {
2663                if is_sampled == 2 {
2664                    return Err(Error::InvalidImageDepthStorage);
2665                }
2666
2667                crate::ImageClass::Depth { multi: is_msaa }
2668            }
2669            // If we have an unknown format and storage texture, this is
2670            // StorageRead/WriteWithoutFormat. We don't currently support
2671            // this.
2672            else if is_sampled == 2 && format == 0 {
2673                return Err(Error::InvalidStorageImageWithoutFormat);
2674            }
2675            // If we have explicit class information (is_sampled = 2 = Storage), use it.
2676            //
2677            // If we have unknown class information (is_sampled = 0 = Unknown), infer the
2678            // class from the presence of an explicit format.
2679            else if format != 0 && (is_sampled == 0 || is_sampled == 2) {
2680                crate::ImageClass::Storage {
2681                    format: map_image_format(format)?,
2682                    access: crate::StorageAccess::default(),
2683                }
2684            }
2685            // We will hit this case either when sampled is 1, or if we have unknown
2686            // sampling information or when sampled is 0 and we have no explicit format.
2687            else {
2688                crate::ImageClass::Sampled {
2689                    kind,
2690                    multi: is_msaa,
2691                }
2692            },
2693            dim,
2694            arrayed: is_array,
2695        };
2696
2697        let handle = module.types.insert(
2698            crate::Type {
2699                name: decor.name,
2700                inner,
2701            },
2702            self.span_from_with_op(start),
2703        );
2704
2705        self.lookup_type.insert(
2706            id,
2707            LookupType {
2708                handle,
2709                base_id: Some(sample_type_id),
2710            },
2711        );
2712        Ok(())
2713    }
2714
2715    fn parse_type_sampled_image(&mut self, inst: Instruction) -> Result<(), Error> {
2716        self.switch(ModuleState::Type, inst.op)?;
2717        inst.expect(3)?;
2718        let id = self.next()?;
2719        let image_id = self.next()?;
2720        self.lookup_type.insert(
2721            id,
2722            LookupType {
2723                handle: self.lookup_type.lookup(image_id)?.handle,
2724                base_id: Some(image_id),
2725            },
2726        );
2727        Ok(())
2728    }
2729
2730    fn parse_type_sampler(
2731        &mut self,
2732        inst: Instruction,
2733        module: &mut crate::Module,
2734    ) -> Result<(), Error> {
2735        let start = self.data_offset;
2736        self.switch(ModuleState::Type, inst.op)?;
2737        inst.expect(2)?;
2738        let id = self.next()?;
2739        let decor = self.future_decor.remove(&id).unwrap_or_default();
2740        let handle = module.types.insert(
2741            crate::Type {
2742                name: decor.name,
2743                inner: crate::TypeInner::Sampler { comparison: false },
2744            },
2745            self.span_from_with_op(start),
2746        );
2747        self.lookup_type.insert(
2748            id,
2749            LookupType {
2750                handle,
2751                base_id: None,
2752            },
2753        );
2754        Ok(())
2755    }
2756
2757    fn parse_constant(
2758        &mut self,
2759        inst: Instruction,
2760        module: &mut crate::Module,
2761    ) -> Result<(), Error> {
2762        let start = self.data_offset;
2763        self.switch(ModuleState::Type, inst.op)?;
2764        inst.expect_at_least(4)?;
2765        let type_id = self.next()?;
2766        let id = self.next()?;
2767        let type_lookup = self.lookup_type.lookup(type_id)?;
2768        let ty = type_lookup.handle;
2769
2770        let literal = match module.types[ty].inner {
2771            crate::TypeInner::Scalar(crate::Scalar {
2772                kind: crate::ScalarKind::Uint,
2773                width,
2774            }) => {
2775                let low = self.next()?;
2776                match width {
2777                    4 => crate::Literal::U32(low),
2778                    8 => {
2779                        inst.expect(5)?;
2780                        let high = self.next()?;
2781                        crate::Literal::U64((u64::from(high) << 32) | u64::from(low))
2782                    }
2783                    _ => return Err(Error::InvalidTypeWidth(width as u32)),
2784                }
2785            }
2786            crate::TypeInner::Scalar(crate::Scalar {
2787                kind: crate::ScalarKind::Sint,
2788                width,
2789            }) => {
2790                let low = self.next()?;
2791                match width {
2792                    4 => crate::Literal::I32(low as i32),
2793                    8 => {
2794                        inst.expect(5)?;
2795                        let high = self.next()?;
2796                        crate::Literal::I64(((u64::from(high) << 32) | u64::from(low)) as i64)
2797                    }
2798                    _ => return Err(Error::InvalidTypeWidth(width as u32)),
2799                }
2800            }
2801            crate::TypeInner::Scalar(crate::Scalar {
2802                kind: crate::ScalarKind::Float,
2803                width,
2804            }) => {
2805                let low = self.next()?;
2806                match width {
2807                    // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Literal
2808                    // If a numeric type’s bit width is less than 32-bits, the value appears in the low-order bits of the word.
2809                    2 => crate::Literal::F16(f16::from_bits(low as u16)),
2810                    4 => crate::Literal::F32(f32::from_bits(low)),
2811                    8 => {
2812                        inst.expect(5)?;
2813                        let high = self.next()?;
2814                        crate::Literal::F64(f64::from_bits(
2815                            (u64::from(high) << 32) | u64::from(low),
2816                        ))
2817                    }
2818                    _ => return Err(Error::InvalidTypeWidth(width as u32)),
2819                }
2820            }
2821            _ => return Err(Error::UnsupportedType(type_lookup.handle)),
2822        };
2823
2824        let span = self.span_from_with_op(start);
2825
2826        let init = module
2827            .global_expressions
2828            .append(crate::Expression::Literal(literal), span);
2829
2830        self.insert_parsed_constant(module, id, type_id, ty, init, span)
2831    }
2832
2833    fn parse_composite_constant(
2834        &mut self,
2835        inst: Instruction,
2836        module: &mut crate::Module,
2837    ) -> Result<(), Error> {
2838        let start = self.data_offset;
2839        self.switch(ModuleState::Type, inst.op)?;
2840        inst.expect_at_least(3)?;
2841        let type_id = self.next()?;
2842        let id = self.next()?;
2843
2844        let type_lookup = self.lookup_type.lookup(type_id)?;
2845        let ty = type_lookup.handle;
2846
2847        let mut components = Vec::with_capacity(inst.wc as usize - 3);
2848        for _ in 0..components.capacity() {
2849            let start = self.data_offset;
2850            let component_id = self.next()?;
2851            let span = self.span_from_with_op(start);
2852            let constant = self.lookup_constant.lookup(component_id)?;
2853            let expr = module
2854                .global_expressions
2855                .append(constant.inner.to_expr(), span);
2856            components.push(expr);
2857        }
2858
2859        let span = self.span_from_with_op(start);
2860
2861        let init = module
2862            .global_expressions
2863            .append(crate::Expression::Compose { ty, components }, span);
2864
2865        self.insert_parsed_constant(module, id, type_id, ty, init, span)
2866    }
2867
2868    fn parse_null_constant(
2869        &mut self,
2870        inst: Instruction,
2871        module: &mut crate::Module,
2872    ) -> Result<(), Error> {
2873        let start = self.data_offset;
2874        self.switch(ModuleState::Type, inst.op)?;
2875        inst.expect(3)?;
2876        let type_id = self.next()?;
2877        let id = self.next()?;
2878        let span = self.span_from_with_op(start);
2879
2880        let type_lookup = self.lookup_type.lookup(type_id)?;
2881        let ty = type_lookup.handle;
2882
2883        let init = module
2884            .global_expressions
2885            .append(crate::Expression::ZeroValue(ty), span);
2886
2887        self.insert_parsed_constant(module, id, type_id, ty, init, span)
2888    }
2889
2890    fn parse_bool_constant(
2891        &mut self,
2892        inst: Instruction,
2893        value: bool,
2894        module: &mut crate::Module,
2895    ) -> Result<(), Error> {
2896        let start = self.data_offset;
2897        self.switch(ModuleState::Type, inst.op)?;
2898        inst.expect(3)?;
2899        let type_id = self.next()?;
2900        let id = self.next()?;
2901        let span = self.span_from_with_op(start);
2902
2903        let type_lookup = self.lookup_type.lookup(type_id)?;
2904        let ty = type_lookup.handle;
2905
2906        let init = module.global_expressions.append(
2907            crate::Expression::Literal(crate::Literal::Bool(value)),
2908            span,
2909        );
2910
2911        self.insert_parsed_constant(module, id, type_id, ty, init, span)
2912    }
2913
2914    fn insert_parsed_constant(
2915        &mut self,
2916        module: &mut crate::Module,
2917        id: u32,
2918        type_id: u32,
2919        ty: Handle<crate::Type>,
2920        init: Handle<crate::Expression>,
2921        span: crate::Span,
2922    ) -> Result<(), Error> {
2923        let decor = self.future_decor.remove(&id).unwrap_or_default();
2924
2925        let inner = if let Some(id) = decor.specialization_constant_id {
2926            let o = crate::Override {
2927                name: decor.name,
2928                id: Some(id.try_into().map_err(|_| Error::SpecIdTooHigh(id))?),
2929                ty,
2930                init: Some(init),
2931            };
2932            Constant::Override(module.overrides.append(o, span))
2933        } else {
2934            let c = crate::Constant {
2935                name: decor.name,
2936                ty,
2937                init,
2938            };
2939            Constant::Constant(module.constants.append(c, span))
2940        };
2941
2942        self.lookup_constant
2943            .insert(id, LookupConstant { inner, type_id });
2944        Ok(())
2945    }
2946
2947    fn parse_global_variable(
2948        &mut self,
2949        inst: Instruction,
2950        module: &mut crate::Module,
2951    ) -> Result<(), Error> {
2952        let start = self.data_offset;
2953        self.switch(ModuleState::Type, inst.op)?;
2954        inst.expect_at_least(4)?;
2955        let type_id = self.next()?;
2956        let id = self.next()?;
2957        let storage_class = self.next()?;
2958        let init = if inst.wc > 4 {
2959            inst.expect(5)?;
2960            let start = self.data_offset;
2961            let init_id = self.next()?;
2962            let span = self.span_from_with_op(start);
2963            let lconst = self.lookup_constant.lookup(init_id)?;
2964            let expr = module
2965                .global_expressions
2966                .append(lconst.inner.to_expr(), span);
2967            Some(expr)
2968        } else {
2969            None
2970        };
2971        let span = self.span_from_with_op(start);
2972        let dec = self.future_decor.remove(&id).unwrap_or_default();
2973
2974        let original_ty = self.lookup_type.lookup(type_id)?.handle;
2975        let mut ty = original_ty;
2976
2977        if let crate::TypeInner::Pointer { base, space: _ } = module.types[original_ty].inner {
2978            ty = base;
2979        }
2980
2981        if let crate::TypeInner::BindingArray { .. } = module.types[original_ty].inner {
2982            // Inside `parse_type_array()` we guess that an array of images or
2983            // samplers must be a binding array, and here we validate that guess
2984            if dec.desc_set.is_none() || dec.desc_index.is_none() {
2985                return Err(Error::NonBindingArrayOfImageOrSamplers);
2986            }
2987        }
2988
2989        if let crate::TypeInner::Image {
2990            dim,
2991            arrayed,
2992            class: crate::ImageClass::Storage { format, access: _ },
2993        } = module.types[ty].inner
2994        {
2995            // Storage image types in IR have to contain the access, but not in the SPIR-V.
2996            // The same image type in SPIR-V can be used (and has to be used) for multiple images.
2997            // So we copy the type out and apply the variable access decorations.
2998            let access = dec.flags.to_storage_access();
2999
3000            ty = module.types.insert(
3001                crate::Type {
3002                    name: None,
3003                    inner: crate::TypeInner::Image {
3004                        dim,
3005                        arrayed,
3006                        class: crate::ImageClass::Storage { format, access },
3007                    },
3008                },
3009                Default::default(),
3010            );
3011        }
3012
3013        let ext_class = match self.lookup_storage_buffer_types.get(&ty) {
3014            Some(&access) => ExtendedClass::Global(crate::AddressSpace::Storage { access }),
3015            None => map_storage_class(storage_class)?,
3016        };
3017
3018        let (inner, var) = match ext_class {
3019            ExtendedClass::Global(mut space) => {
3020                if let crate::AddressSpace::Storage { ref mut access } = space {
3021                    *access &= dec.flags.to_storage_access();
3022                }
3023                let var = crate::GlobalVariable {
3024                    binding: dec.resource_binding(),
3025                    name: dec.name,
3026                    space,
3027                    ty,
3028                    init,
3029                    memory_decorations: dec.flags.to_memory_decorations(),
3030                };
3031                (Variable::Global, var)
3032            }
3033            ExtendedClass::Input => {
3034                let binding = dec.io_binding()?;
3035                let mut unsigned_ty = ty;
3036                if let crate::Binding::BuiltIn(built_in) = binding {
3037                    let needs_inner_uint = match built_in {
3038                        crate::BuiltIn::BaseInstance
3039                        | crate::BuiltIn::BaseVertex
3040                        | crate::BuiltIn::InstanceIndex
3041                        | crate::BuiltIn::SampleIndex
3042                        | crate::BuiltIn::VertexIndex
3043                        | crate::BuiltIn::PrimitiveIndex
3044                        | crate::BuiltIn::LocalInvocationIndex => {
3045                            Some(crate::TypeInner::Scalar(crate::Scalar::U32))
3046                        }
3047                        crate::BuiltIn::GlobalInvocationId
3048                        | crate::BuiltIn::LocalInvocationId
3049                        | crate::BuiltIn::WorkGroupId
3050                        | crate::BuiltIn::WorkGroupSize => Some(crate::TypeInner::Vector {
3051                            size: crate::VectorSize::Tri,
3052                            scalar: crate::Scalar::U32,
3053                        }),
3054                        crate::BuiltIn::Barycentric { perspective: false } => {
3055                            Some(crate::TypeInner::Vector {
3056                                size: crate::VectorSize::Tri,
3057                                scalar: crate::Scalar::F32,
3058                            })
3059                        }
3060                        _ => None,
3061                    };
3062                    if let (Some(inner), Some(crate::ScalarKind::Sint)) =
3063                        (needs_inner_uint, module.types[ty].inner.scalar_kind())
3064                    {
3065                        unsigned_ty = module
3066                            .types
3067                            .insert(crate::Type { name: None, inner }, Default::default());
3068                    }
3069                }
3070
3071                let var = crate::GlobalVariable {
3072                    name: dec.name.clone(),
3073                    space: crate::AddressSpace::Private,
3074                    binding: None,
3075                    ty,
3076                    init: None,
3077                    memory_decorations: crate::MemoryDecorations::empty(),
3078                };
3079
3080                let inner = Variable::Input(crate::FunctionArgument {
3081                    name: dec.name,
3082                    ty: unsigned_ty,
3083                    binding: Some(binding),
3084                });
3085                (inner, var)
3086            }
3087            ExtendedClass::Output => {
3088                // For output interface blocks, this would be a structure.
3089                let binding = dec.io_binding().ok();
3090                let init = match binding {
3091                    Some(crate::Binding::BuiltIn(built_in)) => {
3092                        match null::generate_default_built_in(
3093                            Some(built_in),
3094                            ty,
3095                            &mut module.global_expressions,
3096                            span,
3097                        ) {
3098                            Ok(handle) => Some(handle),
3099                            Err(e) => {
3100                                log::warn!("Failed to initialize output built-in: {e}");
3101                                None
3102                            }
3103                        }
3104                    }
3105                    Some(crate::Binding::Location { .. }) => None,
3106                    None => match module.types[ty].inner {
3107                        crate::TypeInner::Struct { ref members, .. } => {
3108                            let mut components = Vec::with_capacity(members.len());
3109                            for member in members.iter() {
3110                                let built_in = match member.binding {
3111                                    Some(crate::Binding::BuiltIn(built_in)) => Some(built_in),
3112                                    _ => None,
3113                                };
3114                                let handle = null::generate_default_built_in(
3115                                    built_in,
3116                                    member.ty,
3117                                    &mut module.global_expressions,
3118                                    span,
3119                                )?;
3120                                components.push(handle);
3121                            }
3122                            Some(
3123                                module
3124                                    .global_expressions
3125                                    .append(crate::Expression::Compose { ty, components }, span),
3126                            )
3127                        }
3128                        _ => None,
3129                    },
3130                };
3131
3132                let var = crate::GlobalVariable {
3133                    name: dec.name,
3134                    space: crate::AddressSpace::Private,
3135                    binding: None,
3136                    ty,
3137                    init,
3138                    memory_decorations: crate::MemoryDecorations::empty(),
3139                };
3140                let inner = Variable::Output(crate::FunctionResult { ty, binding });
3141                (inner, var)
3142            }
3143        };
3144
3145        let handle = module.global_variables.append(var, span);
3146
3147        if module.types[ty].inner.can_comparison_sample(module) {
3148            log::debug!("\t\ttracking {handle:?} for sampling properties");
3149
3150            self.handle_sampling
3151                .insert(handle, image::SamplingFlags::empty());
3152        }
3153
3154        self.lookup_variable.insert(
3155            id,
3156            LookupVariable {
3157                inner,
3158                handle,
3159                type_id,
3160            },
3161        );
3162        Ok(())
3163    }
3164
3165    /// Record an atomic access to some component of a global variable.
3166    ///
3167    /// Given `handle`, an expression referring to a scalar that has had an
3168    /// atomic operation applied to it, descend into the expression, noting
3169    /// which global variable it ultimately refers to, and which struct fields
3170    /// of that global's value it accesses.
3171    ///
3172    /// Return the handle of the type of the expression.
3173    ///
3174    /// If the expression doesn't actually refer to something in a global
3175    /// variable, we can't upgrade its type in a way that Naga validation would
3176    /// pass, so reject the input instead.
3177    fn record_atomic_access(
3178        &mut self,
3179        ctx: &BlockContext,
3180        handle: Handle<crate::Expression>,
3181    ) -> Result<Handle<crate::Type>, Error> {
3182        log::debug!("\t\tlocating global variable in {handle:?}");
3183        match ctx.expressions[handle] {
3184            crate::Expression::Access { base, index } => {
3185                log::debug!("\t\t  access {handle:?} {index:?}");
3186                let ty = self.record_atomic_access(ctx, base)?;
3187                let crate::TypeInner::Array { base, .. } = ctx.module.types[ty].inner else {
3188                    unreachable!("Atomic operations on Access expressions only work for arrays");
3189                };
3190                Ok(base)
3191            }
3192            crate::Expression::AccessIndex { base, index } => {
3193                log::debug!("\t\t  access index {handle:?} {index:?}");
3194                let ty = self.record_atomic_access(ctx, base)?;
3195                match ctx.module.types[ty].inner {
3196                    crate::TypeInner::Struct { ref members, .. } => {
3197                        let index = index as usize;
3198                        self.upgrade_atomics.insert_field(ty, index);
3199                        Ok(members[index].ty)
3200                    }
3201                    crate::TypeInner::Array { base, .. } => {
3202                        Ok(base)
3203                    }
3204                    _ => unreachable!("Atomic operations on AccessIndex expressions only work for structs and arrays"),
3205                }
3206            }
3207            crate::Expression::GlobalVariable(h) => {
3208                log::debug!("\t\t  found {h:?}");
3209                self.upgrade_atomics.insert_global(h);
3210                Ok(ctx.module.global_variables[h].ty)
3211            }
3212            _ => Err(Error::AtomicUpgradeError(
3213                crate::front::atomic_upgrade::Error::GlobalVariableMissing,
3214            )),
3215        }
3216    }
3217}
3218
3219fn resolve_constant(gctx: crate::proc::GlobalCtx, constant: &Constant) -> Option<u32> {
3220    let constant = match *constant {
3221        Constant::Constant(constant) => constant,
3222        Constant::Override(_) => return None,
3223    };
3224    match gctx.global_expressions[gctx.constants[constant].init] {
3225        crate::Expression::Literal(crate::Literal::U32(id)) => Some(id),
3226        crate::Expression::Literal(crate::Literal::I32(id)) => Some(id as u32),
3227        _ => None,
3228    }
3229}
3230
3231pub fn parse_u8_slice(data: &[u8], options: &Options) -> Result<crate::Module, Error> {
3232    if !data.len().is_multiple_of(4) {
3233        return Err(Error::IncompleteData);
3234    }
3235
3236    let words = data
3237        .chunks(4)
3238        .map(|c| u32::from_le_bytes(c.try_into().unwrap()));
3239    Frontend::new(words, options).parse()
3240}
3241
3242/// Helper function to check if `child` is in the scope of `parent`
3243fn is_parent(mut child: usize, parent: usize, block_ctx: &BlockContext) -> bool {
3244    loop {
3245        if child == parent {
3246            // The child is in the scope parent
3247            break true;
3248        } else if child == 0 {
3249            // Searched finished at the root the child isn't in the parent's body
3250            break false;
3251        }
3252
3253        child = block_ctx.bodies[child].parent;
3254    }
3255}
3256
3257#[cfg(test)]
3258mod test {
3259    use alloc::vec;
3260
3261    #[test]
3262    fn parse() {
3263        let bin = vec![
3264            // Magic number.           Version number: 1.0.
3265            0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00,
3266            // Generator number: 0.    Bound: 0.
3267            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved word: 0.
3268            0x00, 0x00, 0x00, 0x00, // OpMemoryModel.          Logical.
3269            0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // GLSL450.
3270            0x01, 0x00, 0x00, 0x00,
3271        ];
3272        let _ = super::parse_u8_slice(&bin, &Default::default()).unwrap();
3273    }
3274}