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