1mod convert;
31mod error;
32mod function;
33mod image;
34mod null;
35
36pub use error::Error;
37
38use alloc::{borrow::ToOwned, format, string::String, vec, vec::Vec};
39use core::{convert::TryInto, mem, num::NonZeroU32};
40
41use half::f16;
42use petgraph::graphmap::GraphMap;
43
44use super::atomic_upgrade::Upgrades;
45use crate::{
46 arena::{Arena, Handle, UniqueArena},
47 proc::{Alignment, Layouter},
48 FastHashMap, FastHashSet, FastIndexMap,
49};
50use convert::*;
51use function::*;
52
53pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[
54 spirv::Capability::Shader,
55 spirv::Capability::VulkanMemoryModel,
56 spirv::Capability::ClipDistance,
57 spirv::Capability::CullDistance,
58 spirv::Capability::SampleRateShading,
59 spirv::Capability::DerivativeControl,
60 spirv::Capability::Matrix,
61 spirv::Capability::ImageQuery,
62 spirv::Capability::Sampled1D,
63 spirv::Capability::Image1D,
64 spirv::Capability::SampledCubeArray,
65 spirv::Capability::ImageCubeArray,
66 spirv::Capability::StorageImageExtendedFormats,
67 spirv::Capability::Int8,
68 spirv::Capability::Int16,
69 spirv::Capability::Int64,
70 spirv::Capability::Int64Atomics,
71 spirv::Capability::Float16,
72 spirv::Capability::AtomicFloat32AddEXT,
73 spirv::Capability::Float64,
74 spirv::Capability::Geometry,
75 spirv::Capability::MultiView,
76 spirv::Capability::StorageBuffer16BitAccess,
77 spirv::Capability::UniformAndStorageBuffer16BitAccess,
78 spirv::Capability::GroupNonUniform,
79 spirv::Capability::GroupNonUniformVote,
80 spirv::Capability::GroupNonUniformArithmetic,
81 spirv::Capability::GroupNonUniformBallot,
82 spirv::Capability::GroupNonUniformShuffle,
83 spirv::Capability::GroupNonUniformShuffleRelative,
84 spirv::Capability::RuntimeDescriptorArray,
85 spirv::Capability::StorageImageMultisample,
86 spirv::Capability::UniformBufferArrayDynamicIndexing,
88 spirv::Capability::StorageBufferArrayDynamicIndexing,
89];
90pub const SUPPORTED_EXTENSIONS: &[&str] = &[
91 "SPV_KHR_storage_buffer_storage_class",
92 "SPV_KHR_vulkan_memory_model",
93 "SPV_KHR_multiview",
94 "SPV_EXT_descriptor_indexing",
95 "SPV_EXT_shader_atomic_float_add",
96 "SPV_KHR_16bit_storage",
97];
98pub const SUPPORTED_EXT_SETS: &[&str] = &["GLSL.std.450"];
99
100#[derive(Copy, Clone)]
101pub struct Instruction {
102 op: spirv::Op,
103 wc: u16,
104}
105
106impl Instruction {
107 const fn expect(self, count: u16) -> Result<(), Error> {
108 if self.wc == count {
109 Ok(())
110 } else {
111 Err(Error::InvalidOperandCount(self.op, self.wc))
112 }
113 }
114
115 fn expect_at_least(self, count: u16) -> Result<u16, Error> {
116 self.wc
117 .checked_sub(count)
118 .ok_or(Error::InvalidOperandCount(self.op, self.wc))
119 }
120}
121
122impl crate::TypeInner {
123 fn can_comparison_sample(&self, module: &crate::Module) -> bool {
124 match *self {
125 crate::TypeInner::Image {
126 class:
127 crate::ImageClass::Sampled {
128 kind: crate::ScalarKind::Float,
129 multi: false,
130 },
131 ..
132 } => true,
133 crate::TypeInner::Sampler { .. } => true,
134 crate::TypeInner::BindingArray { base, .. } => {
135 module.types[base].inner.can_comparison_sample(module)
136 }
137 _ => false,
138 }
139 }
140}
141
142#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
143pub enum ModuleState {
144 Empty,
145 Capability,
146 Extension,
147 ExtInstImport,
148 MemoryModel,
149 EntryPoint,
150 ExecutionMode,
151 Source,
152 Name,
153 ModuleProcessed,
154 Annotation,
155 Type,
156 Function,
157}
158
159trait LookupHelper {
160 type Target;
161 fn lookup(&self, key: spirv::Word) -> Result<&Self::Target, Error>;
162}
163
164impl<T> LookupHelper for FastHashMap<spirv::Word, T> {
165 type Target = T;
166 fn lookup(&self, key: spirv::Word) -> Result<&T, Error> {
167 self.get(&key).ok_or(Error::InvalidId(key))
168 }
169}
170
171impl crate::ImageDimension {
172 const fn required_coordinate_size(&self) -> Option<crate::VectorSize> {
173 match *self {
174 crate::ImageDimension::D1 => None,
175 crate::ImageDimension::D2 => Some(crate::VectorSize::Bi),
176 crate::ImageDimension::D3 => Some(crate::VectorSize::Tri),
177 crate::ImageDimension::Cube => Some(crate::VectorSize::Tri),
178 }
179 }
180}
181
182type MemberIndex = u32;
183
184bitflags::bitflags! {
185 #[derive(Clone, Copy, Debug, Default)]
186 struct DecorationFlags: u32 {
187 const NON_READABLE = 0x1;
188 const NON_WRITABLE = 0x2;
189 }
190}
191
192impl DecorationFlags {
193 fn to_storage_access(self) -> crate::StorageAccess {
194 let mut access = crate::StorageAccess::LOAD | crate::StorageAccess::STORE;
195 if self.contains(DecorationFlags::NON_READABLE) {
196 access &= !crate::StorageAccess::LOAD;
197 }
198 if self.contains(DecorationFlags::NON_WRITABLE) {
199 access &= !crate::StorageAccess::STORE;
200 }
201 access
202 }
203}
204
205#[derive(Debug, PartialEq)]
206enum Majority {
207 Column,
208 Row,
209}
210
211#[derive(Debug, Default)]
212struct Decoration {
213 name: Option<String>,
214 built_in: Option<spirv::Word>,
215 location: Option<spirv::Word>,
216 desc_set: Option<spirv::Word>,
217 desc_index: Option<spirv::Word>,
218 specialization_constant_id: Option<spirv::Word>,
219 storage_buffer: bool,
220 offset: Option<spirv::Word>,
221 array_stride: Option<NonZeroU32>,
222 matrix_stride: Option<NonZeroU32>,
223 matrix_major: Option<Majority>,
224 invariant: bool,
225 interpolation: Option<crate::Interpolation>,
226 sampling: Option<crate::Sampling>,
227 flags: DecorationFlags,
228}
229
230impl Decoration {
231 fn debug_name(&self) -> &str {
232 match self.name {
233 Some(ref name) => name.as_str(),
234 None => "?",
235 }
236 }
237
238 const fn resource_binding(&self) -> Option<crate::ResourceBinding> {
239 match *self {
240 Decoration {
241 desc_set: Some(group),
242 desc_index: Some(binding),
243 ..
244 } => Some(crate::ResourceBinding { group, binding }),
245 _ => None,
246 }
247 }
248
249 fn io_binding(&self) -> Result<crate::Binding, Error> {
250 match *self {
251 Decoration {
252 built_in: Some(built_in),
253 location: None,
254 invariant,
255 ..
256 } => Ok(crate::Binding::BuiltIn(map_builtin(built_in, invariant)?)),
257 Decoration {
258 built_in: None,
259 location: Some(location),
260 interpolation,
261 sampling,
262 ..
263 } => Ok(crate::Binding::Location {
264 location,
265 interpolation,
266 sampling,
267 blend_src: None,
268 }),
269 _ => Err(Error::MissingDecoration(spirv::Decoration::Location)),
270 }
271 }
272}
273
274#[derive(Debug)]
275struct LookupFunctionType {
276 parameter_type_ids: Vec<spirv::Word>,
277 return_type_id: spirv::Word,
278}
279
280struct LookupFunction {
281 handle: Handle<crate::Function>,
282 parameters_sampling: Vec<image::SamplingFlags>,
283}
284
285#[derive(Debug)]
286struct EntryPoint {
287 stage: crate::ShaderStage,
288 name: String,
289 early_depth_test: Option<crate::EarlyDepthTest>,
290 workgroup_size: [u32; 3],
291 variable_ids: Vec<spirv::Word>,
292}
293
294#[derive(Clone, Debug)]
295struct LookupType {
296 handle: Handle<crate::Type>,
297 base_id: Option<spirv::Word>,
298}
299
300#[derive(Debug)]
301enum Constant {
302 Constant(Handle<crate::Constant>),
303 Override(Handle<crate::Override>),
304}
305
306impl Constant {
307 const fn to_expr(&self) -> crate::Expression {
308 match *self {
309 Self::Constant(c) => crate::Expression::Constant(c),
310 Self::Override(o) => crate::Expression::Override(o),
311 }
312 }
313}
314
315#[derive(Debug)]
316struct LookupConstant {
317 inner: Constant,
318 type_id: spirv::Word,
319}
320
321#[derive(Debug)]
322enum Variable {
323 Global,
324 Input(crate::FunctionArgument),
325 Output(crate::FunctionResult),
326}
327
328#[derive(Debug)]
329struct LookupVariable {
330 inner: Variable,
331 handle: Handle<crate::GlobalVariable>,
332 type_id: spirv::Word,
333}
334
335#[derive(Clone, Debug)]
337struct LookupExpression {
338 handle: Handle<crate::Expression>,
345
346 type_id: spirv::Word,
348
349 block_id: spirv::Word,
354}
355
356#[derive(Debug)]
357struct LookupMember {
358 type_id: spirv::Word,
359 row_major: bool,
361}
362
363#[derive(Clone, Debug)]
364enum LookupLoadOverride {
365 Pending,
367 Loaded(Handle<crate::Expression>),
369}
370
371#[derive(PartialEq)]
372enum ExtendedClass {
373 Global(crate::AddressSpace),
374 Input,
375 Output,
376}
377
378#[derive(Clone, Debug)]
379pub struct Options {
380 pub adjust_coordinate_space: bool,
384 pub strict_capabilities: bool,
386 pub block_ctx_dump_prefix: Option<String>,
387}
388
389impl Default for Options {
390 fn default() -> Self {
391 Options {
392 adjust_coordinate_space: true,
393 strict_capabilities: true,
394 block_ctx_dump_prefix: None,
395 }
396 }
397}
398
399type BodyIndex = usize;
401
402#[derive(Debug)]
411enum BodyFragment {
412 BlockId(spirv::Word),
413 If {
414 condition: Handle<crate::Expression>,
415 accept: BodyIndex,
416 reject: BodyIndex,
417 },
418 Loop {
419 body: BodyIndex,
422
423 continuing: BodyIndex,
426
427 break_if: Option<Handle<crate::Expression>>,
431 },
432 Switch {
433 selector: Handle<crate::Expression>,
434 cases: Vec<(i32, BodyIndex)>,
435 default: BodyIndex,
436 },
437 Break,
438 Continue,
439}
440
441#[derive(Debug)]
448struct Body {
449 parent: usize,
451 data: Vec<BodyFragment>,
452}
453
454impl Body {
455 pub const fn with_parent(parent: usize) -> Self {
457 Body {
458 parent,
459 data: Vec::new(),
460 }
461 }
462}
463
464#[derive(Debug)]
465struct PhiExpression {
466 local: Handle<crate::LocalVariable>,
468 expressions: Vec<(spirv::Word, spirv::Word)>,
470}
471
472#[derive(Copy, Clone, Debug, PartialEq, Eq)]
473enum MergeBlockInformation {
474 LoopMerge,
475 LoopContinue,
476 SelectionMerge,
477 SwitchMerge,
478}
479
480#[derive(Debug)]
521struct BlockContext<'function> {
522 phis: Vec<PhiExpression>,
525
526 blocks: FastHashMap<spirv::Word, crate::Block>,
533
534 body_for_label: FastHashMap<spirv::Word, BodyIndex>,
552
553 mergers: FastHashMap<spirv::Word, MergeBlockInformation>,
555
556 bodies: Vec<Body>,
560
561 module: &'function mut crate::Module,
563
564 function_id: spirv::Word,
566 expressions: &'function mut Arena<crate::Expression>,
568 local_arena: &'function mut Arena<crate::LocalVariable>,
570 arguments: &'function [crate::FunctionArgument],
572 parameter_sampling: &'function mut [image::SamplingFlags],
574}
575
576enum SignAnchor {
577 Result,
578 Operand,
579}
580
581pub struct Frontend<I> {
582 data: I,
583 data_offset: usize,
584 state: ModuleState,
585 layouter: Layouter,
586 temp_bytes: Vec<u8>,
587 ext_glsl_id: Option<spirv::Word>,
588 future_decor: FastHashMap<spirv::Word, Decoration>,
589 future_member_decor: FastHashMap<(spirv::Word, MemberIndex), Decoration>,
590 lookup_member: FastHashMap<(Handle<crate::Type>, MemberIndex), LookupMember>,
591 handle_sampling: FastHashMap<Handle<crate::GlobalVariable>, image::SamplingFlags>,
592
593 upgrade_atomics: Upgrades,
598
599 lookup_type: FastHashMap<spirv::Word, LookupType>,
600 lookup_void_type: Option<spirv::Word>,
601 lookup_storage_buffer_types: FastHashMap<Handle<crate::Type>, crate::StorageAccess>,
602 lookup_constant: FastHashMap<spirv::Word, LookupConstant>,
603 lookup_variable: FastHashMap<spirv::Word, LookupVariable>,
604 lookup_expression: FastHashMap<spirv::Word, LookupExpression>,
605 lookup_load_override: FastHashMap<spirv::Word, LookupLoadOverride>,
607 lookup_sampled_image: FastHashMap<spirv::Word, image::LookupSampledImage>,
608 lookup_function_type: FastHashMap<spirv::Word, LookupFunctionType>,
609 lookup_function: FastHashMap<spirv::Word, LookupFunction>,
610 lookup_entry_point: FastHashMap<spirv::Word, EntryPoint>,
611 deferred_entry_points: Vec<(EntryPoint, spirv::Word)>,
614 deferred_function_calls: Vec<spirv::Word>,
617 dummy_functions: Arena<crate::Function>,
618 function_call_graph: GraphMap<
622 spirv::Word,
623 (),
624 petgraph::Directed,
625 core::hash::BuildHasherDefault<rustc_hash::FxHasher>,
626 >,
627 options: Options,
628
629 switch_cases: FastIndexMap<spirv::Word, (BodyIndex, Vec<i32>)>,
634
635 gl_per_vertex_builtin_access: FastHashSet<crate::BuiltIn>,
644}
645
646impl<I: Iterator<Item = u32>> Frontend<I> {
647 pub fn new(data: I, options: &Options) -> Self {
648 Frontend {
649 data,
650 data_offset: 0,
651 state: ModuleState::Empty,
652 layouter: Layouter::default(),
653 temp_bytes: Vec::new(),
654 ext_glsl_id: None,
655 future_decor: FastHashMap::default(),
656 future_member_decor: FastHashMap::default(),
657 handle_sampling: FastHashMap::default(),
658 lookup_member: FastHashMap::default(),
659 upgrade_atomics: Default::default(),
660 lookup_type: FastHashMap::default(),
661 lookup_void_type: None,
662 lookup_storage_buffer_types: FastHashMap::default(),
663 lookup_constant: FastHashMap::default(),
664 lookup_variable: FastHashMap::default(),
665 lookup_expression: FastHashMap::default(),
666 lookup_load_override: FastHashMap::default(),
667 lookup_sampled_image: FastHashMap::default(),
668 lookup_function_type: FastHashMap::default(),
669 lookup_function: FastHashMap::default(),
670 lookup_entry_point: FastHashMap::default(),
671 deferred_entry_points: Vec::default(),
672 deferred_function_calls: Vec::default(),
673 dummy_functions: Arena::new(),
674 function_call_graph: GraphMap::new(),
675 options: options.clone(),
676 switch_cases: FastIndexMap::default(),
677 gl_per_vertex_builtin_access: FastHashSet::default(),
678 }
679 }
680
681 fn span_from(&self, from: usize) -> crate::Span {
682 crate::Span::from(from..self.data_offset)
683 }
684
685 fn span_from_with_op(&self, from: usize) -> crate::Span {
686 crate::Span::from((from - 4)..self.data_offset)
687 }
688
689 fn next(&mut self) -> Result<u32, Error> {
690 if let Some(res) = self.data.next() {
691 self.data_offset += 4;
692 Ok(res)
693 } else {
694 Err(Error::IncompleteData)
695 }
696 }
697
698 fn next_inst(&mut self) -> Result<Instruction, Error> {
699 let word = self.next()?;
700 let (wc, opcode) = ((word >> 16) as u16, (word & 0xffff) as u16);
701 if wc == 0 {
702 return Err(Error::InvalidWordCount);
703 }
704 let op = spirv::Op::from_u32(opcode as u32).ok_or(Error::UnknownInstruction(opcode))?;
705
706 Ok(Instruction { op, wc })
707 }
708
709 fn next_string(&mut self, mut count: u16) -> Result<(String, u16), Error> {
710 self.temp_bytes.clear();
711 loop {
712 if count == 0 {
713 return Err(Error::BadString);
714 }
715 count -= 1;
716 let chars = self.next()?.to_le_bytes();
717 let pos = chars.iter().position(|&c| c == 0).unwrap_or(4);
718 self.temp_bytes.extend_from_slice(&chars[..pos]);
719 if pos < 4 {
720 break;
721 }
722 }
723 core::str::from_utf8(&self.temp_bytes)
724 .map(|s| (s.to_owned(), count))
725 .map_err(|_| Error::BadString)
726 }
727
728 fn next_decoration(
729 &mut self,
730 inst: Instruction,
731 base_words: u16,
732 dec: &mut Decoration,
733 ) -> Result<(), Error> {
734 let raw = self.next()?;
735 let dec_typed = spirv::Decoration::from_u32(raw).ok_or(Error::InvalidDecoration(raw))?;
736 log::trace!("\t\t{}: {:?}", dec.debug_name(), dec_typed);
737 match dec_typed {
738 spirv::Decoration::BuiltIn => {
739 inst.expect(base_words + 2)?;
740 dec.built_in = Some(self.next()?);
741 }
742 spirv::Decoration::Location => {
743 inst.expect(base_words + 2)?;
744 dec.location = Some(self.next()?);
745 }
746 spirv::Decoration::DescriptorSet => {
747 inst.expect(base_words + 2)?;
748 dec.desc_set = Some(self.next()?);
749 }
750 spirv::Decoration::Binding => {
751 inst.expect(base_words + 2)?;
752 dec.desc_index = Some(self.next()?);
753 }
754 spirv::Decoration::BufferBlock => {
755 dec.storage_buffer = true;
756 }
757 spirv::Decoration::Offset => {
758 inst.expect(base_words + 2)?;
759 dec.offset = Some(self.next()?);
760 }
761 spirv::Decoration::ArrayStride => {
762 inst.expect(base_words + 2)?;
763 dec.array_stride = NonZeroU32::new(self.next()?);
764 }
765 spirv::Decoration::MatrixStride => {
766 inst.expect(base_words + 2)?;
767 dec.matrix_stride = NonZeroU32::new(self.next()?);
768 }
769 spirv::Decoration::Invariant => {
770 dec.invariant = true;
771 }
772 spirv::Decoration::NoPerspective => {
773 dec.interpolation = Some(crate::Interpolation::Linear);
774 }
775 spirv::Decoration::Flat => {
776 dec.interpolation = Some(crate::Interpolation::Flat);
777 }
778 spirv::Decoration::Centroid => {
779 dec.sampling = Some(crate::Sampling::Centroid);
780 }
781 spirv::Decoration::Sample => {
782 dec.sampling = Some(crate::Sampling::Sample);
783 }
784 spirv::Decoration::NonReadable => {
785 dec.flags |= DecorationFlags::NON_READABLE;
786 }
787 spirv::Decoration::NonWritable => {
788 dec.flags |= DecorationFlags::NON_WRITABLE;
789 }
790 spirv::Decoration::ColMajor => {
791 dec.matrix_major = Some(Majority::Column);
792 }
793 spirv::Decoration::RowMajor => {
794 dec.matrix_major = Some(Majority::Row);
795 }
796 spirv::Decoration::SpecId => {
797 dec.specialization_constant_id = Some(self.next()?);
798 }
799 other => {
800 log::warn!("Unknown decoration {other:?}");
801 for _ in base_words + 1..inst.wc {
802 let _var = self.next()?;
803 }
804 }
805 }
806 Ok(())
807 }
808
809 fn get_expr_handle(
880 &self,
881 id: spirv::Word,
882 lookup: &LookupExpression,
883 ctx: &mut BlockContext,
884 emitter: &mut crate::proc::Emitter,
885 block: &mut crate::Block,
886 body_idx: BodyIndex,
887 ) -> Handle<crate::Expression> {
888 let expr_body_idx = ctx
890 .body_for_label
891 .get(&lookup.block_id)
892 .copied()
893 .unwrap_or(0);
894
895 if is_parent(body_idx, expr_body_idx, ctx) {
902 lookup.handle
903 } else {
904 let ty = self.lookup_type[&lookup.type_id].handle;
907 let local = ctx.local_arena.append(
908 crate::LocalVariable {
909 name: None,
910 ty,
911 init: None,
912 },
913 crate::Span::default(),
914 );
915
916 block.extend(emitter.finish(ctx.expressions));
917 let pointer = ctx.expressions.append(
918 crate::Expression::LocalVariable(local),
919 crate::Span::default(),
920 );
921 emitter.start(ctx.expressions);
922 let expr = ctx
923 .expressions
924 .append(crate::Expression::Load { pointer }, crate::Span::default());
925
926 ctx.phis.push(PhiExpression {
935 local,
936 expressions: vec![(id, lookup.block_id)],
937 });
938
939 expr
940 }
941 }
942
943 fn parse_expr_unary_op(
944 &mut self,
945 ctx: &mut BlockContext,
946 emitter: &mut crate::proc::Emitter,
947 block: &mut crate::Block,
948 block_id: spirv::Word,
949 body_idx: usize,
950 op: crate::UnaryOperator,
951 ) -> Result<(), Error> {
952 let start = self.data_offset;
953 let result_type_id = self.next()?;
954 let result_id = self.next()?;
955 let p_id = self.next()?;
956
957 let p_lexp = self.lookup_expression.lookup(p_id)?;
958 let handle = self.get_expr_handle(p_id, p_lexp, ctx, emitter, block, body_idx);
959
960 let expr = crate::Expression::Unary { op, expr: handle };
961 self.lookup_expression.insert(
962 result_id,
963 LookupExpression {
964 handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
965 type_id: result_type_id,
966 block_id,
967 },
968 );
969 Ok(())
970 }
971
972 fn parse_expr_binary_op(
973 &mut self,
974 ctx: &mut BlockContext,
975 emitter: &mut crate::proc::Emitter,
976 block: &mut crate::Block,
977 block_id: spirv::Word,
978 body_idx: usize,
979 op: crate::BinaryOperator,
980 ) -> Result<(), Error> {
981 let start = self.data_offset;
982 let result_type_id = self.next()?;
983 let result_id = self.next()?;
984 let p1_id = self.next()?;
985 let p2_id = self.next()?;
986
987 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
988 let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
989 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
990 let right = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
991
992 let expr = crate::Expression::Binary { op, left, right };
993 self.lookup_expression.insert(
994 result_id,
995 LookupExpression {
996 handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
997 type_id: result_type_id,
998 block_id,
999 },
1000 );
1001 Ok(())
1002 }
1003
1004 fn parse_expr_unary_op_sign_adjusted(
1007 &mut self,
1008 ctx: &mut BlockContext,
1009 emitter: &mut crate::proc::Emitter,
1010 block: &mut crate::Block,
1011 block_id: spirv::Word,
1012 body_idx: usize,
1013 op: crate::UnaryOperator,
1014 ) -> Result<(), Error> {
1015 let start = self.data_offset;
1016 let result_type_id = self.next()?;
1017 let result_id = self.next()?;
1018 let p1_id = self.next()?;
1019 let span = self.span_from_with_op(start);
1020
1021 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1022 let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1023
1024 let result_lookup_ty = self.lookup_type.lookup(result_type_id)?;
1025 let kind = ctx.module.types[result_lookup_ty.handle]
1026 .inner
1027 .scalar_kind()
1028 .unwrap();
1029
1030 let expr = crate::Expression::Unary {
1031 op,
1032 expr: if p1_lexp.type_id == result_type_id {
1033 left
1034 } else {
1035 ctx.expressions.append(
1036 crate::Expression::As {
1037 expr: left,
1038 kind,
1039 convert: None,
1040 },
1041 span,
1042 )
1043 },
1044 };
1045
1046 self.lookup_expression.insert(
1047 result_id,
1048 LookupExpression {
1049 handle: ctx.expressions.append(expr, span),
1050 type_id: result_type_id,
1051 block_id,
1052 },
1053 );
1054 Ok(())
1055 }
1056
1057 #[allow(clippy::too_many_arguments)]
1061 fn parse_expr_binary_op_sign_adjusted(
1062 &mut self,
1063 ctx: &mut BlockContext,
1064 emitter: &mut crate::proc::Emitter,
1065 block: &mut crate::Block,
1066 block_id: spirv::Word,
1067 body_idx: usize,
1068 op: crate::BinaryOperator,
1069 anchor: SignAnchor,
1073 ) -> Result<(), Error> {
1074 let start = self.data_offset;
1075 let result_type_id = self.next()?;
1076 let result_id = self.next()?;
1077 let p1_id = self.next()?;
1078 let p2_id = self.next()?;
1079 let span = self.span_from_with_op(start);
1080
1081 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1082 let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1083 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1084 let right = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1085
1086 let expected_type_id = match anchor {
1087 SignAnchor::Result => result_type_id,
1088 SignAnchor::Operand => p1_lexp.type_id,
1089 };
1090 let expected_lookup_ty = self.lookup_type.lookup(expected_type_id)?;
1091 let kind = ctx.module.types[expected_lookup_ty.handle]
1092 .inner
1093 .scalar_kind()
1094 .unwrap();
1095
1096 let expr = crate::Expression::Binary {
1097 op,
1098 left: if p1_lexp.type_id == expected_type_id {
1099 left
1100 } else {
1101 ctx.expressions.append(
1102 crate::Expression::As {
1103 expr: left,
1104 kind,
1105 convert: None,
1106 },
1107 span,
1108 )
1109 },
1110 right: if p2_lexp.type_id == expected_type_id {
1111 right
1112 } else {
1113 ctx.expressions.append(
1114 crate::Expression::As {
1115 expr: right,
1116 kind,
1117 convert: None,
1118 },
1119 span,
1120 )
1121 },
1122 };
1123
1124 self.lookup_expression.insert(
1125 result_id,
1126 LookupExpression {
1127 handle: ctx.expressions.append(expr, span),
1128 type_id: result_type_id,
1129 block_id,
1130 },
1131 );
1132 Ok(())
1133 }
1134
1135 #[allow(clippy::too_many_arguments)]
1139 fn parse_expr_int_comparison(
1140 &mut self,
1141 ctx: &mut BlockContext,
1142 emitter: &mut crate::proc::Emitter,
1143 block: &mut crate::Block,
1144 block_id: spirv::Word,
1145 body_idx: usize,
1146 op: crate::BinaryOperator,
1147 kind: crate::ScalarKind,
1148 ) -> Result<(), Error> {
1149 let start = self.data_offset;
1150 let result_type_id = self.next()?;
1151 let result_id = self.next()?;
1152 let p1_id = self.next()?;
1153 let p2_id = self.next()?;
1154 let span = self.span_from_with_op(start);
1155
1156 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1157 let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1158 let p1_lookup_ty = self.lookup_type.lookup(p1_lexp.type_id)?;
1159 let p1_kind = ctx.module.types[p1_lookup_ty.handle]
1160 .inner
1161 .scalar_kind()
1162 .unwrap();
1163 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1164 let right = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1165 let p2_lookup_ty = self.lookup_type.lookup(p2_lexp.type_id)?;
1166 let p2_kind = ctx.module.types[p2_lookup_ty.handle]
1167 .inner
1168 .scalar_kind()
1169 .unwrap();
1170
1171 let expr = crate::Expression::Binary {
1172 op,
1173 left: if p1_kind == kind {
1174 left
1175 } else {
1176 ctx.expressions.append(
1177 crate::Expression::As {
1178 expr: left,
1179 kind,
1180 convert: None,
1181 },
1182 span,
1183 )
1184 },
1185 right: if p2_kind == kind {
1186 right
1187 } else {
1188 ctx.expressions.append(
1189 crate::Expression::As {
1190 expr: right,
1191 kind,
1192 convert: None,
1193 },
1194 span,
1195 )
1196 },
1197 };
1198
1199 self.lookup_expression.insert(
1200 result_id,
1201 LookupExpression {
1202 handle: ctx.expressions.append(expr, span),
1203 type_id: result_type_id,
1204 block_id,
1205 },
1206 );
1207 Ok(())
1208 }
1209
1210 fn parse_expr_shift_op(
1211 &mut self,
1212 ctx: &mut BlockContext,
1213 emitter: &mut crate::proc::Emitter,
1214 block: &mut crate::Block,
1215 block_id: spirv::Word,
1216 body_idx: usize,
1217 op: crate::BinaryOperator,
1218 ) -> Result<(), Error> {
1219 let start = self.data_offset;
1220 let result_type_id = self.next()?;
1221 let result_id = self.next()?;
1222 let p1_id = self.next()?;
1223 let p2_id = self.next()?;
1224
1225 let span = self.span_from_with_op(start);
1226
1227 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1228 let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1229 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1230 let p2_handle = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1231 let right = ctx.expressions.append(
1233 crate::Expression::As {
1234 expr: p2_handle,
1235 kind: crate::ScalarKind::Uint,
1236 convert: None,
1237 },
1238 span,
1239 );
1240
1241 let expr = crate::Expression::Binary { op, left, right };
1242 self.lookup_expression.insert(
1243 result_id,
1244 LookupExpression {
1245 handle: ctx.expressions.append(expr, span),
1246 type_id: result_type_id,
1247 block_id,
1248 },
1249 );
1250 Ok(())
1251 }
1252
1253 fn parse_expr_derivative(
1254 &mut self,
1255 ctx: &mut BlockContext,
1256 emitter: &mut crate::proc::Emitter,
1257 block: &mut crate::Block,
1258 block_id: spirv::Word,
1259 body_idx: usize,
1260 (axis, ctrl): (crate::DerivativeAxis, crate::DerivativeControl),
1261 ) -> Result<(), Error> {
1262 let start = self.data_offset;
1263 let result_type_id = self.next()?;
1264 let result_id = self.next()?;
1265 let arg_id = self.next()?;
1266
1267 let arg_lexp = self.lookup_expression.lookup(arg_id)?;
1268 let arg_handle = self.get_expr_handle(arg_id, arg_lexp, ctx, emitter, block, body_idx);
1269
1270 let expr = crate::Expression::Derivative {
1271 axis,
1272 ctrl,
1273 expr: arg_handle,
1274 };
1275 self.lookup_expression.insert(
1276 result_id,
1277 LookupExpression {
1278 handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
1279 type_id: result_type_id,
1280 block_id,
1281 },
1282 );
1283 Ok(())
1284 }
1285
1286 #[allow(clippy::too_many_arguments)]
1287 fn insert_composite(
1288 &self,
1289 root_expr: Handle<crate::Expression>,
1290 root_type_id: spirv::Word,
1291 object_expr: Handle<crate::Expression>,
1292 selections: &[spirv::Word],
1293 type_arena: &UniqueArena<crate::Type>,
1294 expressions: &mut Arena<crate::Expression>,
1295 span: crate::Span,
1296 ) -> Result<Handle<crate::Expression>, Error> {
1297 let selection = match selections.first() {
1298 Some(&index) => index,
1299 None => return Ok(object_expr),
1300 };
1301 let root_span = expressions.get_span(root_expr);
1302 let root_lookup = self.lookup_type.lookup(root_type_id)?;
1303
1304 let (count, child_type_id) = match type_arena[root_lookup.handle].inner {
1305 crate::TypeInner::Struct { ref members, .. } => {
1306 let child_member = self
1307 .lookup_member
1308 .get(&(root_lookup.handle, selection))
1309 .ok_or(Error::InvalidAccessType(root_type_id))?;
1310 (members.len(), child_member.type_id)
1311 }
1312 crate::TypeInner::Array { size, .. } => {
1313 let size = match size {
1314 crate::ArraySize::Constant(size) => size.get(),
1315 crate::ArraySize::Pending(_) => {
1316 unreachable!();
1317 }
1318 crate::ArraySize::Dynamic => {
1320 return Err(Error::InvalidAccessType(root_type_id))
1321 }
1322 };
1323
1324 let child_type_id = root_lookup
1325 .base_id
1326 .ok_or(Error::InvalidAccessType(root_type_id))?;
1327
1328 (size as usize, child_type_id)
1329 }
1330 crate::TypeInner::Vector { size, .. }
1331 | crate::TypeInner::Matrix { columns: size, .. } => {
1332 let child_type_id = root_lookup
1333 .base_id
1334 .ok_or(Error::InvalidAccessType(root_type_id))?;
1335 (size as usize, child_type_id)
1336 }
1337 _ => return Err(Error::InvalidAccessType(root_type_id)),
1338 };
1339
1340 let mut components = Vec::with_capacity(count);
1341 for index in 0..count as u32 {
1342 let expr = expressions.append(
1343 crate::Expression::AccessIndex {
1344 base: root_expr,
1345 index,
1346 },
1347 if index == selection { span } else { root_span },
1348 );
1349 components.push(expr);
1350 }
1351 components[selection as usize] = self.insert_composite(
1352 components[selection as usize],
1353 child_type_id,
1354 object_expr,
1355 &selections[1..],
1356 type_arena,
1357 expressions,
1358 span,
1359 )?;
1360
1361 Ok(expressions.append(
1362 crate::Expression::Compose {
1363 ty: root_lookup.handle,
1364 components,
1365 },
1366 span,
1367 ))
1368 }
1369
1370 fn get_exp_and_base_ty_handles(
1384 &self,
1385 pointer_id: spirv::Word,
1386 ctx: &mut BlockContext,
1387 emitter: &mut crate::proc::Emitter,
1388 block: &mut crate::Block,
1389 body_idx: usize,
1390 ) -> Result<(Handle<crate::Expression>, Handle<crate::Type>), Error> {
1391 log::trace!("\t\t\tlooking up pointer expr {pointer_id:?}");
1392 let p_lexp_handle;
1393 let p_lexp_ty_id;
1394 {
1395 let lexp = self.lookup_expression.lookup(pointer_id)?;
1396 p_lexp_handle = self.get_expr_handle(pointer_id, lexp, ctx, emitter, block, body_idx);
1397 p_lexp_ty_id = lexp.type_id;
1398 };
1399
1400 log::trace!("\t\t\tlooking up pointer type {pointer_id:?}");
1401 let p_ty = self.lookup_type.lookup(p_lexp_ty_id)?;
1402 let p_ty_base_id = p_ty.base_id.ok_or(Error::InvalidAccessType(p_lexp_ty_id))?;
1403
1404 log::trace!("\t\t\tlooking up pointer base type {p_ty_base_id:?} of {p_ty:?}");
1405 let p_base_ty = self.lookup_type.lookup(p_ty_base_id)?;
1406
1407 Ok((p_lexp_handle, p_base_ty.handle))
1408 }
1409
1410 #[allow(clippy::too_many_arguments)]
1411 fn parse_atomic_expr_with_value(
1412 &mut self,
1413 inst: Instruction,
1414 emitter: &mut crate::proc::Emitter,
1415 ctx: &mut BlockContext,
1416 block: &mut crate::Block,
1417 block_id: spirv::Word,
1418 body_idx: usize,
1419 atomic_function: crate::AtomicFunction,
1420 ) -> Result<(), Error> {
1421 inst.expect(7)?;
1422 let start = self.data_offset;
1423 let result_type_id = self.next()?;
1424 let result_id = self.next()?;
1425 let pointer_id = self.next()?;
1426 let _scope_id = self.next()?;
1427 let _memory_semantics_id = self.next()?;
1428 let value_id = self.next()?;
1429 let span = self.span_from_with_op(start);
1430
1431 let (p_lexp_handle, p_base_ty_handle) =
1432 self.get_exp_and_base_ty_handles(pointer_id, ctx, emitter, block, body_idx)?;
1433
1434 log::trace!("\t\t\tlooking up value expr {value_id:?}");
1435 let v_lexp_handle = self.lookup_expression.lookup(value_id)?.handle;
1436
1437 block.extend(emitter.finish(ctx.expressions));
1438 let r_lexp_handle = {
1440 let expr = crate::Expression::AtomicResult {
1441 ty: p_base_ty_handle,
1442 comparison: false,
1443 };
1444 let handle = ctx.expressions.append(expr, span);
1445 self.lookup_expression.insert(
1446 result_id,
1447 LookupExpression {
1448 handle,
1449 type_id: result_type_id,
1450 block_id,
1451 },
1452 );
1453 handle
1454 };
1455 emitter.start(ctx.expressions);
1456
1457 let stmt = crate::Statement::Atomic {
1459 pointer: p_lexp_handle,
1460 fun: atomic_function,
1461 value: v_lexp_handle,
1462 result: Some(r_lexp_handle),
1463 };
1464 block.push(stmt, span);
1465
1466 self.record_atomic_access(ctx, p_lexp_handle)?;
1468
1469 Ok(())
1470 }
1471
1472 fn next_block(&mut self, block_id: spirv::Word, ctx: &mut BlockContext) -> Result<(), Error> {
1478 fn merger(body: &mut Body, target: &MergeBlockInformation) {
1480 body.data.push(match *target {
1481 MergeBlockInformation::LoopContinue => BodyFragment::Continue,
1482 MergeBlockInformation::LoopMerge | MergeBlockInformation::SwitchMerge => {
1483 BodyFragment::Break
1484 }
1485
1486 MergeBlockInformation::SelectionMerge => return,
1489 })
1490 }
1491
1492 let mut emitter = crate::proc::Emitter::default();
1493 emitter.start(ctx.expressions);
1494
1495 let mut body_idx = *ctx.body_for_label.entry(block_id).or_default();
1509
1510 let mut block = crate::Block::new();
1514
1515 let mut selection_merge_block = None;
1521
1522 macro_rules! get_expr_handle {
1523 ($id:expr, $lexp:expr) => {
1524 self.get_expr_handle($id, $lexp, ctx, &mut emitter, &mut block, body_idx)
1525 };
1526 }
1527 macro_rules! parse_expr_op {
1528 ($op:expr, BINARY) => {
1529 self.parse_expr_binary_op(ctx, &mut emitter, &mut block, block_id, body_idx, $op)
1530 };
1531
1532 ($op:expr, SHIFT) => {
1533 self.parse_expr_shift_op(ctx, &mut emitter, &mut block, block_id, body_idx, $op)
1534 };
1535 ($op:expr, UNARY) => {
1536 self.parse_expr_unary_op(ctx, &mut emitter, &mut block, block_id, body_idx, $op)
1537 };
1538 ($axis:expr, $ctrl:expr, DERIVATIVE) => {
1539 self.parse_expr_derivative(
1540 ctx,
1541 &mut emitter,
1542 &mut block,
1543 block_id,
1544 body_idx,
1545 ($axis, $ctrl),
1546 )
1547 };
1548 }
1549
1550 let terminator = loop {
1551 use spirv::Op;
1552 let start = self.data_offset;
1553 let inst = self.next_inst()?;
1554 let span = crate::Span::from(start..(start + 4 * (inst.wc as usize)));
1555 log::debug!("\t\t{:?} [{}]", inst.op, inst.wc);
1556
1557 match inst.op {
1558 Op::Line => {
1559 inst.expect(4)?;
1560 let _file_id = self.next()?;
1561 let _row_id = self.next()?;
1562 let _col_id = self.next()?;
1563 }
1564 Op::NoLine => inst.expect(1)?,
1565 Op::Undef => {
1566 inst.expect(3)?;
1567 let type_id = self.next()?;
1568 let id = self.next()?;
1569 let type_lookup = self.lookup_type.lookup(type_id)?;
1570 let ty = type_lookup.handle;
1571
1572 self.lookup_expression.insert(
1573 id,
1574 LookupExpression {
1575 handle: ctx
1576 .expressions
1577 .append(crate::Expression::ZeroValue(ty), span),
1578 type_id,
1579 block_id,
1580 },
1581 );
1582 }
1583 Op::Variable => {
1584 inst.expect_at_least(4)?;
1585 block.extend(emitter.finish(ctx.expressions));
1586
1587 let result_type_id = self.next()?;
1588 let result_id = self.next()?;
1589 let _storage_class = self.next()?;
1590 let init = if inst.wc > 4 {
1591 inst.expect(5)?;
1592 let init_id = self.next()?;
1593 let lconst = self.lookup_constant.lookup(init_id)?;
1594 Some(ctx.expressions.append(lconst.inner.to_expr(), span))
1595 } else {
1596 None
1597 };
1598
1599 let name = self
1600 .future_decor
1601 .remove(&result_id)
1602 .and_then(|decor| decor.name);
1603 if let Some(ref name) = name {
1604 log::debug!("\t\t\tid={result_id} name={name}");
1605 }
1606 let lookup_ty = self.lookup_type.lookup(result_type_id)?;
1607 let var_handle = ctx.local_arena.append(
1608 crate::LocalVariable {
1609 name,
1610 ty: match ctx.module.types[lookup_ty.handle].inner {
1611 crate::TypeInner::Pointer { base, .. } => base,
1612 _ => lookup_ty.handle,
1613 },
1614 init,
1615 },
1616 span,
1617 );
1618
1619 self.lookup_expression.insert(
1620 result_id,
1621 LookupExpression {
1622 handle: ctx
1623 .expressions
1624 .append(crate::Expression::LocalVariable(var_handle), span),
1625 type_id: result_type_id,
1626 block_id,
1627 },
1628 );
1629 emitter.start(ctx.expressions);
1630 }
1631 Op::Phi => {
1632 inst.expect_at_least(3)?;
1633 block.extend(emitter.finish(ctx.expressions));
1634
1635 let result_type_id = self.next()?;
1636 let result_id = self.next()?;
1637
1638 let name = format!("phi_{result_id}");
1639 let local = ctx.local_arena.append(
1640 crate::LocalVariable {
1641 name: Some(name),
1642 ty: self.lookup_type.lookup(result_type_id)?.handle,
1643 init: None,
1644 },
1645 self.span_from(start),
1646 );
1647 let pointer = ctx
1648 .expressions
1649 .append(crate::Expression::LocalVariable(local), span);
1650
1651 let in_count = (inst.wc - 3) / 2;
1652 let mut phi = PhiExpression {
1653 local,
1654 expressions: Vec::with_capacity(in_count as usize),
1655 };
1656 for _ in 0..in_count {
1657 let expr = self.next()?;
1658 let block = self.next()?;
1659 phi.expressions.push((expr, block));
1660 }
1661
1662 ctx.phis.push(phi);
1663 emitter.start(ctx.expressions);
1664
1665 self.lookup_expression.insert(
1668 result_id,
1669 LookupExpression {
1670 handle: ctx
1671 .expressions
1672 .append(crate::Expression::Load { pointer }, span),
1673 type_id: result_type_id,
1674 block_id,
1675 },
1676 );
1677 }
1678 Op::AccessChain | Op::InBoundsAccessChain => {
1679 struct AccessExpression {
1680 base_handle: Handle<crate::Expression>,
1681 type_id: spirv::Word,
1682 load_override: Option<LookupLoadOverride>,
1683 }
1684
1685 inst.expect_at_least(4)?;
1686
1687 let result_type_id = self.next()?;
1688 let result_id = self.next()?;
1689 let base_id = self.next()?;
1690 log::trace!("\t\t\tlooking up expr {base_id:?}");
1691
1692 let mut acex = {
1693 let lexp = self.lookup_expression.lookup(base_id)?;
1694 let lty = self.lookup_type.lookup(lexp.type_id)?;
1695
1696 let dereference = match ctx.module.types[lty.handle].inner {
1706 crate::TypeInner::BindingArray { .. } => false,
1707 _ => true,
1708 };
1709
1710 let type_id = if dereference {
1711 lty.base_id.ok_or(Error::InvalidAccessType(lexp.type_id))?
1712 } else {
1713 lexp.type_id
1714 };
1715
1716 AccessExpression {
1717 base_handle: get_expr_handle!(base_id, lexp),
1718 type_id,
1719 load_override: self.lookup_load_override.get(&base_id).cloned(),
1720 }
1721 };
1722
1723 for _ in 4..inst.wc {
1724 let access_id = self.next()?;
1725 log::trace!("\t\t\tlooking up index expr {access_id:?}");
1726 let index_expr = self.lookup_expression.lookup(access_id)?.clone();
1727 let index_expr_handle = get_expr_handle!(access_id, &index_expr);
1728 let index_expr_data = &ctx.expressions[index_expr.handle];
1729 let index_maybe = match *index_expr_data {
1730 crate::Expression::Constant(const_handle) => Some(
1731 ctx.gctx()
1732 .eval_expr_to_u32(ctx.module.constants[const_handle].init)
1733 .map_err(|_| {
1734 Error::InvalidAccess(crate::Expression::Constant(
1735 const_handle,
1736 ))
1737 })?,
1738 ),
1739 _ => None,
1740 };
1741
1742 log::trace!("\t\t\tlooking up type {:?}", acex.type_id);
1743 let type_lookup = self.lookup_type.lookup(acex.type_id)?;
1744 let ty = &ctx.module.types[type_lookup.handle];
1745 acex = match ty.inner {
1746 crate::TypeInner::Struct { ref members, .. } => {
1748 let index = index_maybe
1749 .ok_or_else(|| Error::InvalidAccess(index_expr_data.clone()))?;
1750
1751 let lookup_member = self
1752 .lookup_member
1753 .get(&(type_lookup.handle, index))
1754 .ok_or(Error::InvalidAccessType(acex.type_id))?;
1755 let base_handle = ctx.expressions.append(
1756 crate::Expression::AccessIndex {
1757 base: acex.base_handle,
1758 index,
1759 },
1760 span,
1761 );
1762
1763 if let Some(crate::Binding::BuiltIn(built_in)) =
1764 members[index as usize].binding
1765 {
1766 self.gl_per_vertex_builtin_access.insert(built_in);
1767 }
1768
1769 AccessExpression {
1770 base_handle,
1771 type_id: lookup_member.type_id,
1772 load_override: if lookup_member.row_major {
1773 debug_assert!(acex.load_override.is_none());
1774 let sub_type_lookup =
1775 self.lookup_type.lookup(lookup_member.type_id)?;
1776 Some(match ctx.module.types[sub_type_lookup.handle].inner {
1777 crate::TypeInner::Matrix { .. } => {
1779 let loaded = ctx.expressions.append(
1780 crate::Expression::Load {
1781 pointer: base_handle,
1782 },
1783 span,
1784 );
1785 let transposed = ctx.expressions.append(
1786 crate::Expression::Math {
1787 fun: crate::MathFunction::Transpose,
1788 arg: loaded,
1789 arg1: None,
1790 arg2: None,
1791 arg3: None,
1792 },
1793 span,
1794 );
1795 LookupLoadOverride::Loaded(transposed)
1796 }
1797 _ => LookupLoadOverride::Pending,
1798 })
1799 } else {
1800 None
1801 },
1802 }
1803 }
1804 crate::TypeInner::Matrix { .. } => {
1805 let load_override = match acex.load_override {
1806 Some(LookupLoadOverride::Loaded(load_expr)) => {
1808 let index = index_maybe.ok_or_else(|| {
1809 Error::InvalidAccess(index_expr_data.clone())
1810 })?;
1811 let sub_handle = ctx.expressions.append(
1812 crate::Expression::AccessIndex {
1813 base: load_expr,
1814 index,
1815 },
1816 span,
1817 );
1818 Some(LookupLoadOverride::Loaded(sub_handle))
1819 }
1820 _ => None,
1821 };
1822 let sub_expr = match index_maybe {
1823 Some(index) => crate::Expression::AccessIndex {
1824 base: acex.base_handle,
1825 index,
1826 },
1827 None => crate::Expression::Access {
1828 base: acex.base_handle,
1829 index: index_expr_handle,
1830 },
1831 };
1832 AccessExpression {
1833 base_handle: ctx.expressions.append(sub_expr, span),
1834 type_id: type_lookup
1835 .base_id
1836 .ok_or(Error::InvalidAccessType(acex.type_id))?,
1837 load_override,
1838 }
1839 }
1840 _ => {
1842 let base_handle = ctx.expressions.append(
1843 crate::Expression::Access {
1844 base: acex.base_handle,
1845 index: index_expr_handle,
1846 },
1847 span,
1848 );
1849 let load_override = match acex.load_override {
1850 Some(lookup_load_override) => {
1853 let sub_expr = match lookup_load_override {
1854 LookupLoadOverride::Pending => {
1857 let loaded = ctx.expressions.append(
1858 crate::Expression::Load {
1859 pointer: base_handle,
1860 },
1861 span,
1862 );
1863 ctx.expressions.append(
1864 crate::Expression::Math {
1865 fun: crate::MathFunction::Transpose,
1866 arg: loaded,
1867 arg1: None,
1868 arg2: None,
1869 arg3: None,
1870 },
1871 span,
1872 )
1873 }
1874 LookupLoadOverride::Loaded(load_expr) => {
1876 ctx.expressions.append(
1877 crate::Expression::Access {
1878 base: load_expr,
1879 index: index_expr_handle,
1880 },
1881 span,
1882 )
1883 }
1884 };
1885 Some(LookupLoadOverride::Loaded(sub_expr))
1886 }
1887 None => None,
1888 };
1889 AccessExpression {
1890 base_handle,
1891 type_id: type_lookup
1892 .base_id
1893 .ok_or(Error::InvalidAccessType(acex.type_id))?,
1894 load_override,
1895 }
1896 }
1897 };
1898 }
1899
1900 if let Some(load_expr) = acex.load_override {
1901 self.lookup_load_override.insert(result_id, load_expr);
1902 }
1903 let lookup_expression = LookupExpression {
1904 handle: acex.base_handle,
1905 type_id: result_type_id,
1906 block_id,
1907 };
1908 self.lookup_expression.insert(result_id, lookup_expression);
1909 }
1910 Op::VectorExtractDynamic => {
1911 inst.expect(5)?;
1912
1913 let result_type_id = self.next()?;
1914 let id = self.next()?;
1915 let composite_id = self.next()?;
1916 let index_id = self.next()?;
1917
1918 let root_lexp = self.lookup_expression.lookup(composite_id)?;
1919 let root_handle = get_expr_handle!(composite_id, root_lexp);
1920 let root_type_lookup = self.lookup_type.lookup(root_lexp.type_id)?;
1921 let index_lexp = self.lookup_expression.lookup(index_id)?;
1922 let index_handle = get_expr_handle!(index_id, index_lexp);
1923 let index_type = self.lookup_type.lookup(index_lexp.type_id)?.handle;
1924
1925 let num_components = match ctx.module.types[root_type_lookup.handle].inner {
1926 crate::TypeInner::Vector { size, .. } => size as u32,
1927 _ => return Err(Error::InvalidVectorType(root_type_lookup.handle)),
1928 };
1929
1930 let mut make_index = |ctx: &mut BlockContext, index: u32| {
1931 make_index_literal(
1932 ctx,
1933 index,
1934 &mut block,
1935 &mut emitter,
1936 index_type,
1937 index_lexp.type_id,
1938 span,
1939 )
1940 };
1941
1942 let index_expr = make_index(ctx, 0)?;
1943 let mut handle = ctx.expressions.append(
1944 crate::Expression::Access {
1945 base: root_handle,
1946 index: index_expr,
1947 },
1948 span,
1949 );
1950 for index in 1..num_components {
1951 let index_expr = make_index(ctx, index)?;
1952 let access_expr = ctx.expressions.append(
1953 crate::Expression::Access {
1954 base: root_handle,
1955 index: index_expr,
1956 },
1957 span,
1958 );
1959 let cond = ctx.expressions.append(
1960 crate::Expression::Binary {
1961 op: crate::BinaryOperator::Equal,
1962 left: index_expr,
1963 right: index_handle,
1964 },
1965 span,
1966 );
1967 handle = ctx.expressions.append(
1968 crate::Expression::Select {
1969 condition: cond,
1970 accept: access_expr,
1971 reject: handle,
1972 },
1973 span,
1974 );
1975 }
1976
1977 self.lookup_expression.insert(
1978 id,
1979 LookupExpression {
1980 handle,
1981 type_id: result_type_id,
1982 block_id,
1983 },
1984 );
1985 }
1986 Op::VectorInsertDynamic => {
1987 inst.expect(6)?;
1988
1989 let result_type_id = self.next()?;
1990 let id = self.next()?;
1991 let composite_id = self.next()?;
1992 let object_id = self.next()?;
1993 let index_id = self.next()?;
1994
1995 let object_lexp = self.lookup_expression.lookup(object_id)?;
1996 let object_handle = get_expr_handle!(object_id, object_lexp);
1997 let root_lexp = self.lookup_expression.lookup(composite_id)?;
1998 let root_handle = get_expr_handle!(composite_id, root_lexp);
1999 let root_type_lookup = self.lookup_type.lookup(root_lexp.type_id)?;
2000 let index_lexp = self.lookup_expression.lookup(index_id)?;
2001 let index_handle = get_expr_handle!(index_id, index_lexp);
2002 let index_type = self.lookup_type.lookup(index_lexp.type_id)?.handle;
2003
2004 let num_components = match ctx.module.types[root_type_lookup.handle].inner {
2005 crate::TypeInner::Vector { size, .. } => size as u32,
2006 _ => return Err(Error::InvalidVectorType(root_type_lookup.handle)),
2007 };
2008
2009 let mut components = Vec::with_capacity(num_components as usize);
2010 for index in 0..num_components {
2011 let index_expr = make_index_literal(
2012 ctx,
2013 index,
2014 &mut block,
2015 &mut emitter,
2016 index_type,
2017 index_lexp.type_id,
2018 span,
2019 )?;
2020 let access_expr = ctx.expressions.append(
2021 crate::Expression::Access {
2022 base: root_handle,
2023 index: index_expr,
2024 },
2025 span,
2026 );
2027 let cond = ctx.expressions.append(
2028 crate::Expression::Binary {
2029 op: crate::BinaryOperator::Equal,
2030 left: index_expr,
2031 right: index_handle,
2032 },
2033 span,
2034 );
2035 let handle = ctx.expressions.append(
2036 crate::Expression::Select {
2037 condition: cond,
2038 accept: object_handle,
2039 reject: access_expr,
2040 },
2041 span,
2042 );
2043 components.push(handle);
2044 }
2045 let handle = ctx.expressions.append(
2046 crate::Expression::Compose {
2047 ty: root_type_lookup.handle,
2048 components,
2049 },
2050 span,
2051 );
2052
2053 self.lookup_expression.insert(
2054 id,
2055 LookupExpression {
2056 handle,
2057 type_id: result_type_id,
2058 block_id,
2059 },
2060 );
2061 }
2062 Op::CompositeExtract => {
2063 inst.expect_at_least(4)?;
2064
2065 let result_type_id = self.next()?;
2066 let result_id = self.next()?;
2067 let base_id = self.next()?;
2068 log::trace!("\t\t\tlooking up expr {base_id:?}");
2069 let mut lexp = self.lookup_expression.lookup(base_id)?.clone();
2070 lexp.handle = get_expr_handle!(base_id, &lexp);
2071 for _ in 4..inst.wc {
2072 let index = self.next()?;
2073 log::trace!("\t\t\tlooking up type {:?}", lexp.type_id);
2074 let type_lookup = self.lookup_type.lookup(lexp.type_id)?;
2075 let type_id = match ctx.module.types[type_lookup.handle].inner {
2076 crate::TypeInner::Struct { .. } => {
2077 self.lookup_member
2078 .get(&(type_lookup.handle, index))
2079 .ok_or(Error::InvalidAccessType(lexp.type_id))?
2080 .type_id
2081 }
2082 crate::TypeInner::Array { .. }
2083 | crate::TypeInner::Vector { .. }
2084 | crate::TypeInner::Matrix { .. } => type_lookup
2085 .base_id
2086 .ok_or(Error::InvalidAccessType(lexp.type_id))?,
2087 ref other => {
2088 log::warn!("composite type {other:?}");
2089 return Err(Error::UnsupportedType(type_lookup.handle));
2090 }
2091 };
2092 lexp = LookupExpression {
2093 handle: ctx.expressions.append(
2094 crate::Expression::AccessIndex {
2095 base: lexp.handle,
2096 index,
2097 },
2098 span,
2099 ),
2100 type_id,
2101 block_id,
2102 };
2103 }
2104
2105 self.lookup_expression.insert(
2106 result_id,
2107 LookupExpression {
2108 handle: lexp.handle,
2109 type_id: result_type_id,
2110 block_id,
2111 },
2112 );
2113 }
2114 Op::CompositeInsert => {
2115 inst.expect_at_least(5)?;
2116
2117 let result_type_id = self.next()?;
2118 let id = self.next()?;
2119 let object_id = self.next()?;
2120 let composite_id = self.next()?;
2121 let mut selections = Vec::with_capacity(inst.wc as usize - 5);
2122 for _ in 5..inst.wc {
2123 selections.push(self.next()?);
2124 }
2125
2126 let object_lexp = self.lookup_expression.lookup(object_id)?.clone();
2127 let object_handle = get_expr_handle!(object_id, &object_lexp);
2128 let root_lexp = self.lookup_expression.lookup(composite_id)?.clone();
2129 let root_handle = get_expr_handle!(composite_id, &root_lexp);
2130 let handle = self.insert_composite(
2131 root_handle,
2132 result_type_id,
2133 object_handle,
2134 &selections,
2135 &ctx.module.types,
2136 ctx.expressions,
2137 span,
2138 )?;
2139
2140 self.lookup_expression.insert(
2141 id,
2142 LookupExpression {
2143 handle,
2144 type_id: result_type_id,
2145 block_id,
2146 },
2147 );
2148 }
2149 Op::CompositeConstruct => {
2150 inst.expect_at_least(3)?;
2151
2152 let result_type_id = self.next()?;
2153 let id = self.next()?;
2154 let mut components = Vec::with_capacity(inst.wc as usize - 2);
2155 for _ in 3..inst.wc {
2156 let comp_id = self.next()?;
2157 log::trace!("\t\t\tlooking up expr {comp_id:?}");
2158 let lexp = self.lookup_expression.lookup(comp_id)?;
2159 let handle = get_expr_handle!(comp_id, lexp);
2160 components.push(handle);
2161 }
2162 let ty = self.lookup_type.lookup(result_type_id)?.handle;
2163 let first = components[0];
2164 let expr = match ctx.module.types[ty].inner {
2165 crate::TypeInner::Vector { size, .. }
2167 if components.len() == size as usize
2168 && components[1..].iter().all(|&c| c == first) =>
2169 {
2170 crate::Expression::Splat { size, value: first }
2171 }
2172 _ => crate::Expression::Compose { ty, components },
2173 };
2174 self.lookup_expression.insert(
2175 id,
2176 LookupExpression {
2177 handle: ctx.expressions.append(expr, span),
2178 type_id: result_type_id,
2179 block_id,
2180 },
2181 );
2182 }
2183 Op::Load => {
2184 inst.expect_at_least(4)?;
2185
2186 let result_type_id = self.next()?;
2187 let result_id = self.next()?;
2188 let pointer_id = self.next()?;
2189 if inst.wc != 4 {
2190 inst.expect(5)?;
2191 let _memory_access = self.next()?;
2192 }
2193
2194 let base_lexp = self.lookup_expression.lookup(pointer_id)?;
2195 let base_handle = get_expr_handle!(pointer_id, base_lexp);
2196 let type_lookup = self.lookup_type.lookup(base_lexp.type_id)?;
2197 let handle = match ctx.module.types[type_lookup.handle].inner {
2198 crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } => {
2199 base_handle
2200 }
2201 _ => match self.lookup_load_override.get(&pointer_id) {
2202 Some(&LookupLoadOverride::Loaded(handle)) => handle,
2203 _ => ctx.expressions.append(
2205 crate::Expression::Load {
2206 pointer: base_handle,
2207 },
2208 span,
2209 ),
2210 },
2211 };
2212
2213 self.lookup_expression.insert(
2214 result_id,
2215 LookupExpression {
2216 handle,
2217 type_id: result_type_id,
2218 block_id,
2219 },
2220 );
2221 }
2222 Op::Store => {
2223 inst.expect_at_least(3)?;
2224
2225 let pointer_id = self.next()?;
2226 let value_id = self.next()?;
2227 if inst.wc != 3 {
2228 inst.expect(4)?;
2229 let _memory_access = self.next()?;
2230 }
2231 let base_expr = self.lookup_expression.lookup(pointer_id)?;
2232 let base_handle = get_expr_handle!(pointer_id, base_expr);
2233 let value_expr = self.lookup_expression.lookup(value_id)?;
2234 let value_handle = get_expr_handle!(value_id, value_expr);
2235
2236 block.extend(emitter.finish(ctx.expressions));
2237 block.push(
2238 crate::Statement::Store {
2239 pointer: base_handle,
2240 value: value_handle,
2241 },
2242 span,
2243 );
2244 emitter.start(ctx.expressions);
2245 }
2246 Op::SNegate | Op::FNegate => {
2248 inst.expect(4)?;
2249 self.parse_expr_unary_op_sign_adjusted(
2250 ctx,
2251 &mut emitter,
2252 &mut block,
2253 block_id,
2254 body_idx,
2255 crate::UnaryOperator::Negate,
2256 )?;
2257 }
2258 Op::IAdd
2259 | Op::ISub
2260 | Op::IMul
2261 | Op::BitwiseOr
2262 | Op::BitwiseXor
2263 | Op::BitwiseAnd
2264 | Op::SDiv
2265 | Op::SRem => {
2266 inst.expect(5)?;
2267 let operator = map_binary_operator(inst.op)?;
2268 self.parse_expr_binary_op_sign_adjusted(
2269 ctx,
2270 &mut emitter,
2271 &mut block,
2272 block_id,
2273 body_idx,
2274 operator,
2275 SignAnchor::Result,
2276 )?;
2277 }
2278 Op::IEqual | Op::INotEqual => {
2279 inst.expect(5)?;
2280 let operator = map_binary_operator(inst.op)?;
2281 self.parse_expr_binary_op_sign_adjusted(
2282 ctx,
2283 &mut emitter,
2284 &mut block,
2285 block_id,
2286 body_idx,
2287 operator,
2288 SignAnchor::Operand,
2289 )?;
2290 }
2291 Op::FAdd => {
2292 inst.expect(5)?;
2293 parse_expr_op!(crate::BinaryOperator::Add, BINARY)?;
2294 }
2295 Op::FSub => {
2296 inst.expect(5)?;
2297 parse_expr_op!(crate::BinaryOperator::Subtract, BINARY)?;
2298 }
2299 Op::FMul => {
2300 inst.expect(5)?;
2301 parse_expr_op!(crate::BinaryOperator::Multiply, BINARY)?;
2302 }
2303 Op::UDiv | Op::FDiv => {
2304 inst.expect(5)?;
2305 parse_expr_op!(crate::BinaryOperator::Divide, BINARY)?;
2306 }
2307 Op::UMod | Op::FRem => {
2308 inst.expect(5)?;
2309 parse_expr_op!(crate::BinaryOperator::Modulo, BINARY)?;
2310 }
2311 Op::SMod => {
2312 inst.expect(5)?;
2313
2314 let start = self.data_offset;
2317 let result_type_id = self.next()?;
2318 let result_id = self.next()?;
2319 let p1_id = self.next()?;
2320 let p2_id = self.next()?;
2321 let span = self.span_from_with_op(start);
2322
2323 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
2324 let left = self.get_expr_handle(
2325 p1_id,
2326 p1_lexp,
2327 ctx,
2328 &mut emitter,
2329 &mut block,
2330 body_idx,
2331 );
2332 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
2333 let right = self.get_expr_handle(
2334 p2_id,
2335 p2_lexp,
2336 ctx,
2337 &mut emitter,
2338 &mut block,
2339 body_idx,
2340 );
2341
2342 let result_ty = self.lookup_type.lookup(result_type_id)?;
2343 let inner = &ctx.module.types[result_ty.handle].inner;
2344 let kind = inner.scalar_kind().unwrap();
2345 let size = inner.size(ctx.gctx()) as u8;
2346
2347 let left_cast = ctx.expressions.append(
2348 crate::Expression::As {
2349 expr: left,
2350 kind: crate::ScalarKind::Float,
2351 convert: Some(size),
2352 },
2353 span,
2354 );
2355 let right_cast = ctx.expressions.append(
2356 crate::Expression::As {
2357 expr: right,
2358 kind: crate::ScalarKind::Float,
2359 convert: Some(size),
2360 },
2361 span,
2362 );
2363 let div = ctx.expressions.append(
2364 crate::Expression::Binary {
2365 op: crate::BinaryOperator::Divide,
2366 left: left_cast,
2367 right: right_cast,
2368 },
2369 span,
2370 );
2371 let floor = ctx.expressions.append(
2372 crate::Expression::Math {
2373 fun: crate::MathFunction::Floor,
2374 arg: div,
2375 arg1: None,
2376 arg2: None,
2377 arg3: None,
2378 },
2379 span,
2380 );
2381 let cast = ctx.expressions.append(
2382 crate::Expression::As {
2383 expr: floor,
2384 kind,
2385 convert: Some(size),
2386 },
2387 span,
2388 );
2389 let mult = ctx.expressions.append(
2390 crate::Expression::Binary {
2391 op: crate::BinaryOperator::Multiply,
2392 left: cast,
2393 right,
2394 },
2395 span,
2396 );
2397 let sub = ctx.expressions.append(
2398 crate::Expression::Binary {
2399 op: crate::BinaryOperator::Subtract,
2400 left,
2401 right: mult,
2402 },
2403 span,
2404 );
2405 self.lookup_expression.insert(
2406 result_id,
2407 LookupExpression {
2408 handle: sub,
2409 type_id: result_type_id,
2410 block_id,
2411 },
2412 );
2413 }
2414 Op::FMod => {
2415 inst.expect(5)?;
2416
2417 let start = self.data_offset;
2420 let span = self.span_from_with_op(start);
2421
2422 let result_type_id = self.next()?;
2423 let result_id = self.next()?;
2424 let p1_id = self.next()?;
2425 let p2_id = self.next()?;
2426
2427 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
2428 let left = self.get_expr_handle(
2429 p1_id,
2430 p1_lexp,
2431 ctx,
2432 &mut emitter,
2433 &mut block,
2434 body_idx,
2435 );
2436 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
2437 let right = self.get_expr_handle(
2438 p2_id,
2439 p2_lexp,
2440 ctx,
2441 &mut emitter,
2442 &mut block,
2443 body_idx,
2444 );
2445
2446 let div = ctx.expressions.append(
2447 crate::Expression::Binary {
2448 op: crate::BinaryOperator::Divide,
2449 left,
2450 right,
2451 },
2452 span,
2453 );
2454 let floor = ctx.expressions.append(
2455 crate::Expression::Math {
2456 fun: crate::MathFunction::Floor,
2457 arg: div,
2458 arg1: None,
2459 arg2: None,
2460 arg3: None,
2461 },
2462 span,
2463 );
2464 let mult = ctx.expressions.append(
2465 crate::Expression::Binary {
2466 op: crate::BinaryOperator::Multiply,
2467 left: floor,
2468 right,
2469 },
2470 span,
2471 );
2472 let sub = ctx.expressions.append(
2473 crate::Expression::Binary {
2474 op: crate::BinaryOperator::Subtract,
2475 left,
2476 right: mult,
2477 },
2478 span,
2479 );
2480 self.lookup_expression.insert(
2481 result_id,
2482 LookupExpression {
2483 handle: sub,
2484 type_id: result_type_id,
2485 block_id,
2486 },
2487 );
2488 }
2489 Op::VectorTimesScalar
2490 | Op::VectorTimesMatrix
2491 | Op::MatrixTimesScalar
2492 | Op::MatrixTimesVector
2493 | Op::MatrixTimesMatrix => {
2494 inst.expect(5)?;
2495 parse_expr_op!(crate::BinaryOperator::Multiply, BINARY)?;
2496 }
2497 Op::Transpose => {
2498 inst.expect(4)?;
2499
2500 let result_type_id = self.next()?;
2501 let result_id = self.next()?;
2502 let matrix_id = self.next()?;
2503 let matrix_lexp = self.lookup_expression.lookup(matrix_id)?;
2504 let matrix_handle = get_expr_handle!(matrix_id, matrix_lexp);
2505 let expr = crate::Expression::Math {
2506 fun: crate::MathFunction::Transpose,
2507 arg: matrix_handle,
2508 arg1: None,
2509 arg2: None,
2510 arg3: None,
2511 };
2512 self.lookup_expression.insert(
2513 result_id,
2514 LookupExpression {
2515 handle: ctx.expressions.append(expr, span),
2516 type_id: result_type_id,
2517 block_id,
2518 },
2519 );
2520 }
2521 Op::Dot => {
2522 inst.expect(5)?;
2523
2524 let result_type_id = self.next()?;
2525 let result_id = self.next()?;
2526 let left_id = self.next()?;
2527 let right_id = self.next()?;
2528 let left_lexp = self.lookup_expression.lookup(left_id)?;
2529 let left_handle = get_expr_handle!(left_id, left_lexp);
2530 let right_lexp = self.lookup_expression.lookup(right_id)?;
2531 let right_handle = get_expr_handle!(right_id, right_lexp);
2532 let expr = crate::Expression::Math {
2533 fun: crate::MathFunction::Dot,
2534 arg: left_handle,
2535 arg1: Some(right_handle),
2536 arg2: None,
2537 arg3: None,
2538 };
2539 self.lookup_expression.insert(
2540 result_id,
2541 LookupExpression {
2542 handle: ctx.expressions.append(expr, span),
2543 type_id: result_type_id,
2544 block_id,
2545 },
2546 );
2547 }
2548 Op::BitFieldInsert => {
2549 inst.expect(7)?;
2550
2551 let start = self.data_offset;
2552 let span = self.span_from_with_op(start);
2553
2554 let result_type_id = self.next()?;
2555 let result_id = self.next()?;
2556 let base_id = self.next()?;
2557 let insert_id = self.next()?;
2558 let offset_id = self.next()?;
2559 let count_id = self.next()?;
2560 let base_lexp = self.lookup_expression.lookup(base_id)?;
2561 let base_handle = get_expr_handle!(base_id, base_lexp);
2562 let insert_lexp = self.lookup_expression.lookup(insert_id)?;
2563 let insert_handle = get_expr_handle!(insert_id, insert_lexp);
2564 let offset_lexp = self.lookup_expression.lookup(offset_id)?;
2565 let offset_handle = get_expr_handle!(offset_id, offset_lexp);
2566 let offset_lookup_ty = self.lookup_type.lookup(offset_lexp.type_id)?;
2567 let count_lexp = self.lookup_expression.lookup(count_id)?;
2568 let count_handle = get_expr_handle!(count_id, count_lexp);
2569 let count_lookup_ty = self.lookup_type.lookup(count_lexp.type_id)?;
2570
2571 let offset_kind = ctx.module.types[offset_lookup_ty.handle]
2572 .inner
2573 .scalar_kind()
2574 .unwrap();
2575 let count_kind = ctx.module.types[count_lookup_ty.handle]
2576 .inner
2577 .scalar_kind()
2578 .unwrap();
2579
2580 let offset_cast_handle = if offset_kind != crate::ScalarKind::Uint {
2581 ctx.expressions.append(
2582 crate::Expression::As {
2583 expr: offset_handle,
2584 kind: crate::ScalarKind::Uint,
2585 convert: None,
2586 },
2587 span,
2588 )
2589 } else {
2590 offset_handle
2591 };
2592
2593 let count_cast_handle = if count_kind != crate::ScalarKind::Uint {
2594 ctx.expressions.append(
2595 crate::Expression::As {
2596 expr: count_handle,
2597 kind: crate::ScalarKind::Uint,
2598 convert: None,
2599 },
2600 span,
2601 )
2602 } else {
2603 count_handle
2604 };
2605
2606 let expr = crate::Expression::Math {
2607 fun: crate::MathFunction::InsertBits,
2608 arg: base_handle,
2609 arg1: Some(insert_handle),
2610 arg2: Some(offset_cast_handle),
2611 arg3: Some(count_cast_handle),
2612 };
2613 self.lookup_expression.insert(
2614 result_id,
2615 LookupExpression {
2616 handle: ctx.expressions.append(expr, span),
2617 type_id: result_type_id,
2618 block_id,
2619 },
2620 );
2621 }
2622 Op::BitFieldSExtract | Op::BitFieldUExtract => {
2623 inst.expect(6)?;
2624
2625 let result_type_id = self.next()?;
2626 let result_id = self.next()?;
2627 let base_id = self.next()?;
2628 let offset_id = self.next()?;
2629 let count_id = self.next()?;
2630 let base_lexp = self.lookup_expression.lookup(base_id)?;
2631 let base_handle = get_expr_handle!(base_id, base_lexp);
2632 let offset_lexp = self.lookup_expression.lookup(offset_id)?;
2633 let offset_handle = get_expr_handle!(offset_id, offset_lexp);
2634 let offset_lookup_ty = self.lookup_type.lookup(offset_lexp.type_id)?;
2635 let count_lexp = self.lookup_expression.lookup(count_id)?;
2636 let count_handle = get_expr_handle!(count_id, count_lexp);
2637 let count_lookup_ty = self.lookup_type.lookup(count_lexp.type_id)?;
2638
2639 let offset_kind = ctx.module.types[offset_lookup_ty.handle]
2640 .inner
2641 .scalar_kind()
2642 .unwrap();
2643 let count_kind = ctx.module.types[count_lookup_ty.handle]
2644 .inner
2645 .scalar_kind()
2646 .unwrap();
2647
2648 let offset_cast_handle = if offset_kind != crate::ScalarKind::Uint {
2649 ctx.expressions.append(
2650 crate::Expression::As {
2651 expr: offset_handle,
2652 kind: crate::ScalarKind::Uint,
2653 convert: None,
2654 },
2655 span,
2656 )
2657 } else {
2658 offset_handle
2659 };
2660
2661 let count_cast_handle = if count_kind != crate::ScalarKind::Uint {
2662 ctx.expressions.append(
2663 crate::Expression::As {
2664 expr: count_handle,
2665 kind: crate::ScalarKind::Uint,
2666 convert: None,
2667 },
2668 span,
2669 )
2670 } else {
2671 count_handle
2672 };
2673
2674 let expr = crate::Expression::Math {
2675 fun: crate::MathFunction::ExtractBits,
2676 arg: base_handle,
2677 arg1: Some(offset_cast_handle),
2678 arg2: Some(count_cast_handle),
2679 arg3: None,
2680 };
2681 self.lookup_expression.insert(
2682 result_id,
2683 LookupExpression {
2684 handle: ctx.expressions.append(expr, span),
2685 type_id: result_type_id,
2686 block_id,
2687 },
2688 );
2689 }
2690 Op::BitReverse | Op::BitCount => {
2691 inst.expect(4)?;
2692
2693 let result_type_id = self.next()?;
2694 let result_id = self.next()?;
2695 let base_id = self.next()?;
2696 let base_lexp = self.lookup_expression.lookup(base_id)?;
2697 let base_handle = get_expr_handle!(base_id, base_lexp);
2698 let expr = crate::Expression::Math {
2699 fun: match inst.op {
2700 Op::BitReverse => crate::MathFunction::ReverseBits,
2701 Op::BitCount => crate::MathFunction::CountOneBits,
2702 _ => unreachable!(),
2703 },
2704 arg: base_handle,
2705 arg1: None,
2706 arg2: None,
2707 arg3: None,
2708 };
2709 self.lookup_expression.insert(
2710 result_id,
2711 LookupExpression {
2712 handle: ctx.expressions.append(expr, span),
2713 type_id: result_type_id,
2714 block_id,
2715 },
2716 );
2717 }
2718 Op::OuterProduct => {
2719 inst.expect(5)?;
2720
2721 let result_type_id = self.next()?;
2722 let result_id = self.next()?;
2723 let left_id = self.next()?;
2724 let right_id = self.next()?;
2725 let left_lexp = self.lookup_expression.lookup(left_id)?;
2726 let left_handle = get_expr_handle!(left_id, left_lexp);
2727 let right_lexp = self.lookup_expression.lookup(right_id)?;
2728 let right_handle = get_expr_handle!(right_id, right_lexp);
2729 let expr = crate::Expression::Math {
2730 fun: crate::MathFunction::Outer,
2731 arg: left_handle,
2732 arg1: Some(right_handle),
2733 arg2: None,
2734 arg3: None,
2735 };
2736 self.lookup_expression.insert(
2737 result_id,
2738 LookupExpression {
2739 handle: ctx.expressions.append(expr, span),
2740 type_id: result_type_id,
2741 block_id,
2742 },
2743 );
2744 }
2745 Op::Not => {
2747 inst.expect(4)?;
2748 self.parse_expr_unary_op_sign_adjusted(
2749 ctx,
2750 &mut emitter,
2751 &mut block,
2752 block_id,
2753 body_idx,
2754 crate::UnaryOperator::BitwiseNot,
2755 )?;
2756 }
2757 Op::ShiftRightLogical => {
2758 inst.expect(5)?;
2759 parse_expr_op!(crate::BinaryOperator::ShiftRight, SHIFT)?;
2761 }
2762 Op::ShiftRightArithmetic => {
2763 inst.expect(5)?;
2764 parse_expr_op!(crate::BinaryOperator::ShiftRight, SHIFT)?;
2766 }
2767 Op::ShiftLeftLogical => {
2768 inst.expect(5)?;
2769 parse_expr_op!(crate::BinaryOperator::ShiftLeft, SHIFT)?;
2770 }
2771 Op::Image => {
2773 inst.expect(4)?;
2774 self.parse_image_uncouple(block_id)?;
2775 }
2776 Op::SampledImage => {
2777 inst.expect(5)?;
2778 self.parse_image_couple()?;
2779 }
2780 Op::ImageWrite => {
2781 let extra = inst.expect_at_least(4)?;
2782 let stmt =
2783 self.parse_image_write(extra, ctx, &mut emitter, &mut block, body_idx)?;
2784 block.extend(emitter.finish(ctx.expressions));
2785 block.push(stmt, span);
2786 emitter.start(ctx.expressions);
2787 }
2788 Op::ImageFetch | Op::ImageRead => {
2789 let extra = inst.expect_at_least(5)?;
2790 self.parse_image_load(
2791 extra,
2792 ctx,
2793 &mut emitter,
2794 &mut block,
2795 block_id,
2796 body_idx,
2797 )?;
2798 }
2799 Op::ImageSampleImplicitLod | Op::ImageSampleExplicitLod => {
2800 let extra = inst.expect_at_least(5)?;
2801 let options = image::SamplingOptions {
2802 compare: false,
2803 project: false,
2804 gather: false,
2805 };
2806 self.parse_image_sample(
2807 extra,
2808 options,
2809 ctx,
2810 &mut emitter,
2811 &mut block,
2812 block_id,
2813 body_idx,
2814 )?;
2815 }
2816 Op::ImageSampleProjImplicitLod | Op::ImageSampleProjExplicitLod => {
2817 let extra = inst.expect_at_least(5)?;
2818 let options = image::SamplingOptions {
2819 compare: false,
2820 project: true,
2821 gather: false,
2822 };
2823 self.parse_image_sample(
2824 extra,
2825 options,
2826 ctx,
2827 &mut emitter,
2828 &mut block,
2829 block_id,
2830 body_idx,
2831 )?;
2832 }
2833 Op::ImageSampleDrefImplicitLod | Op::ImageSampleDrefExplicitLod => {
2834 let extra = inst.expect_at_least(6)?;
2835 let options = image::SamplingOptions {
2836 compare: true,
2837 project: false,
2838 gather: false,
2839 };
2840 self.parse_image_sample(
2841 extra,
2842 options,
2843 ctx,
2844 &mut emitter,
2845 &mut block,
2846 block_id,
2847 body_idx,
2848 )?;
2849 }
2850 Op::ImageSampleProjDrefImplicitLod | Op::ImageSampleProjDrefExplicitLod => {
2851 let extra = inst.expect_at_least(6)?;
2852 let options = image::SamplingOptions {
2853 compare: true,
2854 project: true,
2855 gather: false,
2856 };
2857 self.parse_image_sample(
2858 extra,
2859 options,
2860 ctx,
2861 &mut emitter,
2862 &mut block,
2863 block_id,
2864 body_idx,
2865 )?;
2866 }
2867 Op::ImageGather => {
2868 let extra = inst.expect_at_least(6)?;
2869 let options = image::SamplingOptions {
2870 compare: false,
2871 project: false,
2872 gather: true,
2873 };
2874 self.parse_image_sample(
2875 extra,
2876 options,
2877 ctx,
2878 &mut emitter,
2879 &mut block,
2880 block_id,
2881 body_idx,
2882 )?;
2883 }
2884 Op::ImageDrefGather => {
2885 let extra = inst.expect_at_least(6)?;
2886 let options = image::SamplingOptions {
2887 compare: true,
2888 project: false,
2889 gather: true,
2890 };
2891 self.parse_image_sample(
2892 extra,
2893 options,
2894 ctx,
2895 &mut emitter,
2896 &mut block,
2897 block_id,
2898 body_idx,
2899 )?;
2900 }
2901 Op::ImageQuerySize => {
2902 inst.expect(4)?;
2903 self.parse_image_query_size(
2904 false,
2905 ctx,
2906 &mut emitter,
2907 &mut block,
2908 block_id,
2909 body_idx,
2910 )?;
2911 }
2912 Op::ImageQuerySizeLod => {
2913 inst.expect(5)?;
2914 self.parse_image_query_size(
2915 true,
2916 ctx,
2917 &mut emitter,
2918 &mut block,
2919 block_id,
2920 body_idx,
2921 )?;
2922 }
2923 Op::ImageQueryLevels => {
2924 inst.expect(4)?;
2925 self.parse_image_query_other(crate::ImageQuery::NumLevels, ctx, block_id)?;
2926 }
2927 Op::ImageQuerySamples => {
2928 inst.expect(4)?;
2929 self.parse_image_query_other(crate::ImageQuery::NumSamples, ctx, block_id)?;
2930 }
2931 Op::Select => {
2933 inst.expect(6)?;
2934 let result_type_id = self.next()?;
2935 let result_id = self.next()?;
2936 let condition = self.next()?;
2937 let o1_id = self.next()?;
2938 let o2_id = self.next()?;
2939
2940 let cond_lexp = self.lookup_expression.lookup(condition)?;
2941 let cond_handle = get_expr_handle!(condition, cond_lexp);
2942 let o1_lexp = self.lookup_expression.lookup(o1_id)?;
2943 let o1_handle = get_expr_handle!(o1_id, o1_lexp);
2944 let o2_lexp = self.lookup_expression.lookup(o2_id)?;
2945 let o2_handle = get_expr_handle!(o2_id, o2_lexp);
2946
2947 let expr = crate::Expression::Select {
2948 condition: cond_handle,
2949 accept: o1_handle,
2950 reject: o2_handle,
2951 };
2952 self.lookup_expression.insert(
2953 result_id,
2954 LookupExpression {
2955 handle: ctx.expressions.append(expr, span),
2956 type_id: result_type_id,
2957 block_id,
2958 },
2959 );
2960 }
2961 Op::VectorShuffle => {
2962 inst.expect_at_least(5)?;
2963 let result_type_id = self.next()?;
2964 let result_id = self.next()?;
2965 let v1_id = self.next()?;
2966 let v2_id = self.next()?;
2967
2968 let v1_lexp = self.lookup_expression.lookup(v1_id)?;
2969 let v1_lty = self.lookup_type.lookup(v1_lexp.type_id)?;
2970 let v1_handle = get_expr_handle!(v1_id, v1_lexp);
2971 let n1 = match ctx.module.types[v1_lty.handle].inner {
2972 crate::TypeInner::Vector { size, .. } => size as u32,
2973 _ => return Err(Error::InvalidInnerType(v1_lexp.type_id)),
2974 };
2975 let v2_lexp = self.lookup_expression.lookup(v2_id)?;
2976 let v2_lty = self.lookup_type.lookup(v2_lexp.type_id)?;
2977 let v2_handle = get_expr_handle!(v2_id, v2_lexp);
2978 let n2 = match ctx.module.types[v2_lty.handle].inner {
2979 crate::TypeInner::Vector { size, .. } => size as u32,
2980 _ => return Err(Error::InvalidInnerType(v2_lexp.type_id)),
2981 };
2982
2983 self.temp_bytes.clear();
2984 let mut max_component = 0;
2985 for _ in 5..inst.wc as usize {
2986 let mut index = self.next()?;
2987 if index == u32::MAX {
2988 index = 0;
2990 }
2991 max_component = max_component.max(index);
2992 self.temp_bytes.push(index as u8);
2993 }
2994
2995 let expr = if max_component < n1 {
2997 use crate::SwizzleComponent as Sc;
2998 let size = match self.temp_bytes.len() {
2999 2 => crate::VectorSize::Bi,
3000 3 => crate::VectorSize::Tri,
3001 _ => crate::VectorSize::Quad,
3002 };
3003 let mut pattern = [Sc::X; 4];
3004 for (pat, index) in pattern.iter_mut().zip(self.temp_bytes.drain(..)) {
3005 *pat = match index {
3006 0 => Sc::X,
3007 1 => Sc::Y,
3008 2 => Sc::Z,
3009 _ => Sc::W,
3010 };
3011 }
3012 crate::Expression::Swizzle {
3013 size,
3014 vector: v1_handle,
3015 pattern,
3016 }
3017 } else {
3018 let mut components = Vec::with_capacity(self.temp_bytes.len());
3020 for index in self.temp_bytes.drain(..).map(|i| i as u32) {
3021 let expr = if index < n1 {
3022 crate::Expression::AccessIndex {
3023 base: v1_handle,
3024 index,
3025 }
3026 } else if index < n1 + n2 {
3027 crate::Expression::AccessIndex {
3028 base: v2_handle,
3029 index: index - n1,
3030 }
3031 } else {
3032 return Err(Error::InvalidAccessIndex(index));
3033 };
3034 components.push(ctx.expressions.append(expr, span));
3035 }
3036 crate::Expression::Compose {
3037 ty: self.lookup_type.lookup(result_type_id)?.handle,
3038 components,
3039 }
3040 };
3041
3042 self.lookup_expression.insert(
3043 result_id,
3044 LookupExpression {
3045 handle: ctx.expressions.append(expr, span),
3046 type_id: result_type_id,
3047 block_id,
3048 },
3049 );
3050 }
3051 Op::Bitcast
3052 | Op::ConvertSToF
3053 | Op::ConvertUToF
3054 | Op::ConvertFToU
3055 | Op::ConvertFToS
3056 | Op::FConvert
3057 | Op::UConvert
3058 | Op::SConvert => {
3059 inst.expect(4)?;
3060 let result_type_id = self.next()?;
3061 let result_id = self.next()?;
3062 let value_id = self.next()?;
3063
3064 let value_lexp = self.lookup_expression.lookup(value_id)?;
3065 let ty_lookup = self.lookup_type.lookup(result_type_id)?;
3066 let scalar = match ctx.module.types[ty_lookup.handle].inner {
3067 crate::TypeInner::Scalar(scalar)
3068 | crate::TypeInner::Vector { scalar, .. }
3069 | crate::TypeInner::Matrix { scalar, .. } => scalar,
3070 _ => return Err(Error::InvalidAsType(ty_lookup.handle)),
3071 };
3072
3073 let expr = crate::Expression::As {
3074 expr: get_expr_handle!(value_id, value_lexp),
3075 kind: scalar.kind,
3076 convert: if scalar.kind == crate::ScalarKind::Bool {
3077 Some(crate::BOOL_WIDTH)
3078 } else if inst.op == Op::Bitcast {
3079 None
3080 } else {
3081 Some(scalar.width)
3082 },
3083 };
3084 self.lookup_expression.insert(
3085 result_id,
3086 LookupExpression {
3087 handle: ctx.expressions.append(expr, span),
3088 type_id: result_type_id,
3089 block_id,
3090 },
3091 );
3092 }
3093 Op::FunctionCall => {
3094 inst.expect_at_least(4)?;
3095
3096 let result_type_id = self.next()?;
3097 let result_id = self.next()?;
3098 let func_id = self.next()?;
3099
3100 let mut arguments = Vec::with_capacity(inst.wc as usize - 4);
3101 for _ in 0..arguments.capacity() {
3102 let arg_id = self.next()?;
3103 let lexp = self.lookup_expression.lookup(arg_id)?;
3104 arguments.push(get_expr_handle!(arg_id, lexp));
3105 }
3106
3107 block.extend(emitter.finish(ctx.expressions));
3108
3109 let function = self.add_call(ctx.function_id, func_id);
3111
3112 let result = if self.lookup_void_type == Some(result_type_id) {
3113 None
3114 } else {
3115 let expr_handle = ctx
3116 .expressions
3117 .append(crate::Expression::CallResult(function), span);
3118 self.lookup_expression.insert(
3119 result_id,
3120 LookupExpression {
3121 handle: expr_handle,
3122 type_id: result_type_id,
3123 block_id,
3124 },
3125 );
3126 Some(expr_handle)
3127 };
3128 block.push(
3129 crate::Statement::Call {
3130 function,
3131 arguments,
3132 result,
3133 },
3134 span,
3135 );
3136 emitter.start(ctx.expressions);
3137 }
3138 Op::ExtInst => {
3139 use crate::MathFunction as Mf;
3140 use spirv::GLOp as Glo;
3141
3142 let base_wc = 5;
3143 inst.expect_at_least(base_wc)?;
3144
3145 let result_type_id = self.next()?;
3146 let result_id = self.next()?;
3147 let set_id = self.next()?;
3148 if Some(set_id) != self.ext_glsl_id {
3149 return Err(Error::UnsupportedExtInstSet(set_id));
3150 }
3151 let inst_id = self.next()?;
3152 let gl_op = Glo::from_u32(inst_id).ok_or(Error::UnsupportedExtInst(inst_id))?;
3153
3154 let fun = match gl_op {
3155 Glo::Round => Mf::Round,
3156 Glo::RoundEven => Mf::Round,
3157 Glo::Trunc => Mf::Trunc,
3158 Glo::FAbs | Glo::SAbs => Mf::Abs,
3159 Glo::FSign | Glo::SSign => Mf::Sign,
3160 Glo::Floor => Mf::Floor,
3161 Glo::Ceil => Mf::Ceil,
3162 Glo::Fract => Mf::Fract,
3163 Glo::Sin => Mf::Sin,
3164 Glo::Cos => Mf::Cos,
3165 Glo::Tan => Mf::Tan,
3166 Glo::Asin => Mf::Asin,
3167 Glo::Acos => Mf::Acos,
3168 Glo::Atan => Mf::Atan,
3169 Glo::Sinh => Mf::Sinh,
3170 Glo::Cosh => Mf::Cosh,
3171 Glo::Tanh => Mf::Tanh,
3172 Glo::Atan2 => Mf::Atan2,
3173 Glo::Asinh => Mf::Asinh,
3174 Glo::Acosh => Mf::Acosh,
3175 Glo::Atanh => Mf::Atanh,
3176 Glo::Radians => Mf::Radians,
3177 Glo::Degrees => Mf::Degrees,
3178 Glo::Pow => Mf::Pow,
3179 Glo::Exp => Mf::Exp,
3180 Glo::Log => Mf::Log,
3181 Glo::Exp2 => Mf::Exp2,
3182 Glo::Log2 => Mf::Log2,
3183 Glo::Sqrt => Mf::Sqrt,
3184 Glo::InverseSqrt => Mf::InverseSqrt,
3185 Glo::MatrixInverse => Mf::Inverse,
3186 Glo::Determinant => Mf::Determinant,
3187 Glo::ModfStruct => Mf::Modf,
3188 Glo::FMin | Glo::UMin | Glo::SMin | Glo::NMin => Mf::Min,
3189 Glo::FMax | Glo::UMax | Glo::SMax | Glo::NMax => Mf::Max,
3190 Glo::FClamp | Glo::UClamp | Glo::SClamp | Glo::NClamp => Mf::Clamp,
3191 Glo::FMix => Mf::Mix,
3192 Glo::Step => Mf::Step,
3193 Glo::SmoothStep => Mf::SmoothStep,
3194 Glo::Fma => Mf::Fma,
3195 Glo::FrexpStruct => Mf::Frexp,
3196 Glo::Ldexp => Mf::Ldexp,
3197 Glo::Length => Mf::Length,
3198 Glo::Distance => Mf::Distance,
3199 Glo::Cross => Mf::Cross,
3200 Glo::Normalize => Mf::Normalize,
3201 Glo::FaceForward => Mf::FaceForward,
3202 Glo::Reflect => Mf::Reflect,
3203 Glo::Refract => Mf::Refract,
3204 Glo::PackUnorm4x8 => Mf::Pack4x8unorm,
3205 Glo::PackSnorm4x8 => Mf::Pack4x8snorm,
3206 Glo::PackHalf2x16 => Mf::Pack2x16float,
3207 Glo::PackUnorm2x16 => Mf::Pack2x16unorm,
3208 Glo::PackSnorm2x16 => Mf::Pack2x16snorm,
3209 Glo::UnpackUnorm4x8 => Mf::Unpack4x8unorm,
3210 Glo::UnpackSnorm4x8 => Mf::Unpack4x8snorm,
3211 Glo::UnpackHalf2x16 => Mf::Unpack2x16float,
3212 Glo::UnpackUnorm2x16 => Mf::Unpack2x16unorm,
3213 Glo::UnpackSnorm2x16 => Mf::Unpack2x16snorm,
3214 Glo::FindILsb => Mf::FirstTrailingBit,
3215 Glo::FindUMsb | Glo::FindSMsb => Mf::FirstLeadingBit,
3216 Glo::Modf | Glo::Frexp => return Err(Error::UnsupportedExtInst(inst_id)),
3218 Glo::IMix
3219 | Glo::PackDouble2x32
3220 | Glo::UnpackDouble2x32
3221 | Glo::InterpolateAtCentroid
3222 | Glo::InterpolateAtSample
3223 | Glo::InterpolateAtOffset => {
3224 return Err(Error::UnsupportedExtInst(inst_id))
3225 }
3226 };
3227
3228 let arg_count = fun.argument_count();
3229 inst.expect(base_wc + arg_count as u16)?;
3230 let arg = {
3231 let arg_id = self.next()?;
3232 let lexp = self.lookup_expression.lookup(arg_id)?;
3233 get_expr_handle!(arg_id, lexp)
3234 };
3235 let arg1 = if arg_count > 1 {
3236 let arg_id = self.next()?;
3237 let lexp = self.lookup_expression.lookup(arg_id)?;
3238 Some(get_expr_handle!(arg_id, lexp))
3239 } else {
3240 None
3241 };
3242 let arg2 = if arg_count > 2 {
3243 let arg_id = self.next()?;
3244 let lexp = self.lookup_expression.lookup(arg_id)?;
3245 Some(get_expr_handle!(arg_id, lexp))
3246 } else {
3247 None
3248 };
3249 let arg3 = if arg_count > 3 {
3250 let arg_id = self.next()?;
3251 let lexp = self.lookup_expression.lookup(arg_id)?;
3252 Some(get_expr_handle!(arg_id, lexp))
3253 } else {
3254 None
3255 };
3256
3257 let expr = crate::Expression::Math {
3258 fun,
3259 arg,
3260 arg1,
3261 arg2,
3262 arg3,
3263 };
3264 self.lookup_expression.insert(
3265 result_id,
3266 LookupExpression {
3267 handle: ctx.expressions.append(expr, span),
3268 type_id: result_type_id,
3269 block_id,
3270 },
3271 );
3272 }
3273 Op::LogicalNot => {
3275 inst.expect(4)?;
3276 parse_expr_op!(crate::UnaryOperator::LogicalNot, UNARY)?;
3277 }
3278 Op::LogicalOr => {
3279 inst.expect(5)?;
3280 parse_expr_op!(crate::BinaryOperator::LogicalOr, BINARY)?;
3281 }
3282 Op::LogicalAnd => {
3283 inst.expect(5)?;
3284 parse_expr_op!(crate::BinaryOperator::LogicalAnd, BINARY)?;
3285 }
3286 Op::SGreaterThan | Op::SGreaterThanEqual | Op::SLessThan | Op::SLessThanEqual => {
3287 inst.expect(5)?;
3288 self.parse_expr_int_comparison(
3289 ctx,
3290 &mut emitter,
3291 &mut block,
3292 block_id,
3293 body_idx,
3294 map_binary_operator(inst.op)?,
3295 crate::ScalarKind::Sint,
3296 )?;
3297 }
3298 Op::UGreaterThan | Op::UGreaterThanEqual | Op::ULessThan | Op::ULessThanEqual => {
3299 inst.expect(5)?;
3300 self.parse_expr_int_comparison(
3301 ctx,
3302 &mut emitter,
3303 &mut block,
3304 block_id,
3305 body_idx,
3306 map_binary_operator(inst.op)?,
3307 crate::ScalarKind::Uint,
3308 )?;
3309 }
3310 Op::FOrdEqual
3311 | Op::FUnordEqual
3312 | Op::FOrdNotEqual
3313 | Op::FUnordNotEqual
3314 | Op::FOrdLessThan
3315 | Op::FUnordLessThan
3316 | Op::FOrdGreaterThan
3317 | Op::FUnordGreaterThan
3318 | Op::FOrdLessThanEqual
3319 | Op::FUnordLessThanEqual
3320 | Op::FOrdGreaterThanEqual
3321 | Op::FUnordGreaterThanEqual
3322 | Op::LogicalEqual
3323 | Op::LogicalNotEqual => {
3324 inst.expect(5)?;
3325 let operator = map_binary_operator(inst.op)?;
3326 parse_expr_op!(operator, BINARY)?;
3327 }
3328 Op::Any | Op::All | Op::IsNan | Op::IsInf | Op::IsFinite | Op::IsNormal => {
3329 inst.expect(4)?;
3330 let result_type_id = self.next()?;
3331 let result_id = self.next()?;
3332 let arg_id = self.next()?;
3333
3334 let arg_lexp = self.lookup_expression.lookup(arg_id)?;
3335 let arg_handle = get_expr_handle!(arg_id, arg_lexp);
3336
3337 let expr = crate::Expression::Relational {
3338 fun: map_relational_fun(inst.op)?,
3339 argument: arg_handle,
3340 };
3341 self.lookup_expression.insert(
3342 result_id,
3343 LookupExpression {
3344 handle: ctx.expressions.append(expr, span),
3345 type_id: result_type_id,
3346 block_id,
3347 },
3348 );
3349 }
3350 Op::Kill => {
3351 inst.expect(1)?;
3352 break Some(crate::Statement::Kill);
3353 }
3354 Op::Unreachable => {
3355 inst.expect(1)?;
3356 break None;
3357 }
3358 Op::Return => {
3359 inst.expect(1)?;
3360 break Some(crate::Statement::Return { value: None });
3361 }
3362 Op::ReturnValue => {
3363 inst.expect(2)?;
3364 let value_id = self.next()?;
3365 let value_lexp = self.lookup_expression.lookup(value_id)?;
3366 let value_handle = get_expr_handle!(value_id, value_lexp);
3367 break Some(crate::Statement::Return {
3368 value: Some(value_handle),
3369 });
3370 }
3371 Op::Branch => {
3372 inst.expect(2)?;
3373 let target_id = self.next()?;
3374
3375 if let Some(info) = ctx.mergers.get(&target_id) {
3384 block.extend(emitter.finish(ctx.expressions));
3385 ctx.blocks.insert(block_id, block);
3386 let body = &mut ctx.bodies[body_idx];
3387 body.data.push(BodyFragment::BlockId(block_id));
3388
3389 merger(body, info);
3390
3391 return Ok(());
3392 }
3393
3394 ctx.body_for_label.entry(target_id).or_insert(body_idx);
3411
3412 break None;
3413 }
3414 Op::BranchConditional => {
3415 inst.expect_at_least(4)?;
3416
3417 let condition = {
3418 let condition_id = self.next()?;
3419 let lexp = self.lookup_expression.lookup(condition_id)?;
3420 get_expr_handle!(condition_id, lexp)
3421 };
3422
3423 #[derive(Copy, Clone)]
3426 struct BranchTarget {
3427 label_id: spirv::Word,
3428 merge_info: Option<MergeBlockInformation>,
3429 }
3430 let branch_target = |label_id| BranchTarget {
3431 label_id,
3432 merge_info: ctx.mergers.get(&label_id).copied(),
3433 };
3434
3435 let true_target = branch_target(self.next()?);
3436 let false_target = branch_target(self.next()?);
3437
3438 for _ in 4..inst.wc {
3440 let _ = self.next()?;
3441 }
3442
3443 let parent_body_idx = ctx.bodies[body_idx].parent;
3451 let parent_parent_body_idx = ctx.bodies[parent_body_idx].parent;
3452 match ctx.bodies[parent_parent_body_idx].data[..] {
3453 [.., BodyFragment::Loop {
3457 body: loop_body_idx,
3458 continuing: loop_continuing_idx,
3459 break_if: ref mut break_if_slot @ None,
3460 }] if body_idx == loop_continuing_idx => {
3461 let break_if_cond = [true, false].into_iter().find_map(|true_breaks| {
3464 let (break_candidate, backedge_candidate) = if true_breaks {
3465 (true_target, false_target)
3466 } else {
3467 (false_target, true_target)
3468 };
3469
3470 if break_candidate.merge_info
3471 != Some(MergeBlockInformation::LoopMerge)
3472 {
3473 return None;
3474 }
3475
3476 let backedge_candidate_is_backedge =
3480 backedge_candidate.merge_info.is_none()
3481 && ctx.body_for_label.get(&backedge_candidate.label_id)
3482 == Some(&loop_body_idx);
3483 if !backedge_candidate_is_backedge {
3484 return None;
3485 }
3486
3487 Some(if true_breaks {
3488 condition
3489 } else {
3490 ctx.expressions.append(
3491 crate::Expression::Unary {
3492 op: crate::UnaryOperator::LogicalNot,
3493 expr: condition,
3494 },
3495 span,
3496 )
3497 })
3498 });
3499
3500 if let Some(break_if_cond) = break_if_cond {
3501 *break_if_slot = Some(break_if_cond);
3502
3503 break None;
3507 }
3508 }
3509 _ => {}
3510 }
3511
3512 block.extend(emitter.finish(ctx.expressions));
3513 ctx.blocks.insert(block_id, block);
3514 let body = &mut ctx.bodies[body_idx];
3515 body.data.push(BodyFragment::BlockId(block_id));
3516
3517 let same_target = true_target.label_id == false_target.label_id;
3518
3519 let accept = ctx.bodies.len();
3521 let mut accept_block = Body::with_parent(body_idx);
3522
3523 if let Some(info) = true_target.merge_info {
3527 merger(
3528 match same_target {
3529 true => &mut ctx.bodies[body_idx],
3530 false => &mut accept_block,
3531 },
3532 &info,
3533 )
3534 } else {
3535 let prev = ctx.body_for_label.insert(
3537 true_target.label_id,
3538 match same_target {
3539 true => body_idx,
3540 false => accept,
3541 },
3542 );
3543 debug_assert!(prev.is_none());
3544 }
3545
3546 if same_target {
3547 return Ok(());
3548 }
3549
3550 ctx.bodies.push(accept_block);
3551
3552 let reject = ctx.bodies.len();
3554 let mut reject_block = Body::with_parent(body_idx);
3555
3556 if let Some(info) = false_target.merge_info {
3557 merger(&mut reject_block, &info)
3558 } else {
3559 let prev = ctx.body_for_label.insert(false_target.label_id, reject);
3560 debug_assert!(prev.is_none());
3561 }
3562
3563 ctx.bodies.push(reject_block);
3564
3565 let body = &mut ctx.bodies[body_idx];
3566 body.data.push(BodyFragment::If {
3567 condition,
3568 accept,
3569 reject,
3570 });
3571
3572 return Ok(());
3573 }
3574 Op::Switch => {
3575 inst.expect_at_least(3)?;
3576 let selector = self.next()?;
3577 let default_id = self.next()?;
3578
3579 if let Some(merge) = selection_merge_block {
3582 ctx.mergers
3583 .insert(merge, MergeBlockInformation::SwitchMerge);
3584 }
3585
3586 let default = ctx.bodies.len();
3587 ctx.bodies.push(Body::with_parent(body_idx));
3588 ctx.body_for_label.entry(default_id).or_insert(default);
3589
3590 let selector_lexp = &self.lookup_expression[&selector];
3591 let selector_lty = self.lookup_type.lookup(selector_lexp.type_id)?;
3592 let selector_handle = get_expr_handle!(selector, selector_lexp);
3593 let selector = match ctx.module.types[selector_lty.handle].inner {
3594 crate::TypeInner::Scalar(crate::Scalar {
3595 kind: crate::ScalarKind::Uint,
3596 width: _,
3597 }) => {
3598 ctx.expressions.append(
3600 crate::Expression::As {
3601 kind: crate::ScalarKind::Sint,
3602 expr: selector_handle,
3603 convert: None,
3604 },
3605 span,
3606 )
3607 }
3608 crate::TypeInner::Scalar(crate::Scalar {
3609 kind: crate::ScalarKind::Sint,
3610 width: _,
3611 }) => selector_handle,
3612 ref other => unimplemented!("Unexpected selector {:?}", other),
3613 };
3614
3615 self.switch_cases.clear();
3617
3618 for _ in 0..(inst.wc - 3) / 2 {
3619 let literal = self.next()?;
3620 let target = self.next()?;
3621
3622 let case_body_idx = ctx.bodies.len();
3623
3624 if let Some(&mut (_, ref mut literals)) = self.switch_cases.get_mut(&target)
3628 {
3629 literals.push(literal as i32);
3630 continue;
3631 }
3632
3633 let mut body = Body::with_parent(body_idx);
3634
3635 if let Some(info) = ctx.mergers.get(&target) {
3636 merger(&mut body, info);
3637 }
3638
3639 ctx.bodies.push(body);
3640 ctx.body_for_label.entry(target).or_insert(case_body_idx);
3641
3642 self.switch_cases
3645 .insert(target, (case_body_idx, vec![literal as i32]));
3646 }
3647
3648 let mut cases = Vec::with_capacity((inst.wc as usize - 3) / 2);
3657 for &(case_body_idx, ref literals) in self.switch_cases.values() {
3658 let value = literals[0];
3659
3660 for &literal in literals.iter().skip(1) {
3661 let empty_body_idx = ctx.bodies.len();
3662 let body = Body::with_parent(body_idx);
3663
3664 ctx.bodies.push(body);
3665
3666 cases.push((literal, empty_body_idx));
3667 }
3668
3669 cases.push((value, case_body_idx));
3670 }
3671
3672 block.extend(emitter.finish(ctx.expressions));
3673
3674 let body = &mut ctx.bodies[body_idx];
3675 ctx.blocks.insert(block_id, block);
3676 body.data.reserve(2);
3678 body.data.push(BodyFragment::BlockId(block_id));
3679 body.data.push(BodyFragment::Switch {
3680 selector,
3681 cases,
3682 default,
3683 });
3684
3685 return Ok(());
3686 }
3687 Op::SelectionMerge => {
3688 inst.expect(3)?;
3689 let merge_block_id = self.next()?;
3690 let _selection_control = self.next()?;
3692
3693 ctx.body_for_label.entry(merge_block_id).or_insert(body_idx);
3696
3697 ctx.mergers
3700 .insert(merge_block_id, MergeBlockInformation::SelectionMerge);
3701
3702 selection_merge_block = Some(merge_block_id);
3703 }
3704 Op::LoopMerge => {
3705 inst.expect_at_least(4)?;
3706 let merge_block_id = self.next()?;
3707 let continuing = self.next()?;
3708
3709 for _ in 0..inst.wc - 3 {
3711 self.next()?;
3712 }
3713
3714 ctx.body_for_label.entry(merge_block_id).or_insert(body_idx);
3717 ctx.mergers
3720 .insert(merge_block_id, MergeBlockInformation::LoopMerge);
3721
3722 let loop_body_idx = ctx.bodies.len();
3723 ctx.bodies.push(Body::with_parent(body_idx));
3724
3725 let continue_idx = ctx.bodies.len();
3726 ctx.bodies.push(Body::with_parent(loop_body_idx));
3728 ctx.body_for_label.entry(continuing).or_insert(continue_idx);
3729 ctx.mergers
3732 .insert(continuing, MergeBlockInformation::LoopContinue);
3733
3734 ctx.body_for_label.insert(block_id, loop_body_idx);
3736
3737 let parent_body = &mut ctx.bodies[body_idx];
3738 parent_body.data.push(BodyFragment::Loop {
3739 body: loop_body_idx,
3740 continuing: continue_idx,
3741 break_if: None,
3742 });
3743 body_idx = loop_body_idx;
3744 }
3745 Op::DPdxCoarse => {
3746 parse_expr_op!(
3747 crate::DerivativeAxis::X,
3748 crate::DerivativeControl::Coarse,
3749 DERIVATIVE
3750 )?;
3751 }
3752 Op::DPdyCoarse => {
3753 parse_expr_op!(
3754 crate::DerivativeAxis::Y,
3755 crate::DerivativeControl::Coarse,
3756 DERIVATIVE
3757 )?;
3758 }
3759 Op::FwidthCoarse => {
3760 parse_expr_op!(
3761 crate::DerivativeAxis::Width,
3762 crate::DerivativeControl::Coarse,
3763 DERIVATIVE
3764 )?;
3765 }
3766 Op::DPdxFine => {
3767 parse_expr_op!(
3768 crate::DerivativeAxis::X,
3769 crate::DerivativeControl::Fine,
3770 DERIVATIVE
3771 )?;
3772 }
3773 Op::DPdyFine => {
3774 parse_expr_op!(
3775 crate::DerivativeAxis::Y,
3776 crate::DerivativeControl::Fine,
3777 DERIVATIVE
3778 )?;
3779 }
3780 Op::FwidthFine => {
3781 parse_expr_op!(
3782 crate::DerivativeAxis::Width,
3783 crate::DerivativeControl::Fine,
3784 DERIVATIVE
3785 )?;
3786 }
3787 Op::DPdx => {
3788 parse_expr_op!(
3789 crate::DerivativeAxis::X,
3790 crate::DerivativeControl::None,
3791 DERIVATIVE
3792 )?;
3793 }
3794 Op::DPdy => {
3795 parse_expr_op!(
3796 crate::DerivativeAxis::Y,
3797 crate::DerivativeControl::None,
3798 DERIVATIVE
3799 )?;
3800 }
3801 Op::Fwidth => {
3802 parse_expr_op!(
3803 crate::DerivativeAxis::Width,
3804 crate::DerivativeControl::None,
3805 DERIVATIVE
3806 )?;
3807 }
3808 Op::ArrayLength => {
3809 inst.expect(5)?;
3810 let result_type_id = self.next()?;
3811 let result_id = self.next()?;
3812 let structure_id = self.next()?;
3813 let member_index = self.next()?;
3814
3815 let structure_ptr = self.lookup_expression.lookup(structure_id)?;
3819 let structure_handle = get_expr_handle!(structure_id, structure_ptr);
3820
3821 let member_ptr = ctx.expressions.append(
3822 crate::Expression::AccessIndex {
3823 base: structure_handle,
3824 index: member_index,
3825 },
3826 span,
3827 );
3828
3829 let length = ctx
3830 .expressions
3831 .append(crate::Expression::ArrayLength(member_ptr), span);
3832
3833 self.lookup_expression.insert(
3834 result_id,
3835 LookupExpression {
3836 handle: length,
3837 type_id: result_type_id,
3838 block_id,
3839 },
3840 );
3841 }
3842 Op::CopyMemory => {
3843 inst.expect_at_least(3)?;
3844 let target_id = self.next()?;
3845 let source_id = self.next()?;
3846 let _memory_access = if inst.wc != 3 {
3847 inst.expect(4)?;
3848 spirv::MemoryAccess::from_bits(self.next()?)
3849 .ok_or(Error::InvalidParameter(Op::CopyMemory))?
3850 } else {
3851 spirv::MemoryAccess::NONE
3852 };
3853
3854 let target = self.lookup_expression.lookup(target_id)?;
3856 let target_handle = get_expr_handle!(target_id, target);
3857 let source = self.lookup_expression.lookup(source_id)?;
3858 let source_handle = get_expr_handle!(source_id, source);
3859
3860 let value_expr = ctx.expressions.append(
3862 crate::Expression::Load {
3863 pointer: source_handle,
3864 },
3865 span,
3866 );
3867
3868 block.extend(emitter.finish(ctx.expressions));
3869 block.push(
3870 crate::Statement::Store {
3871 pointer: target_handle,
3872 value: value_expr,
3873 },
3874 span,
3875 );
3876
3877 emitter.start(ctx.expressions);
3878 }
3879 Op::ControlBarrier => {
3880 inst.expect(4)?;
3881 let exec_scope_id = self.next()?;
3882 let _mem_scope_raw = self.next()?;
3883 let semantics_id = self.next()?;
3884 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
3885 let semantics_const = self.lookup_constant.lookup(semantics_id)?;
3886
3887 let exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
3888 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
3889 let semantics = resolve_constant(ctx.gctx(), &semantics_const.inner)
3890 .ok_or(Error::InvalidBarrierMemorySemantics(semantics_id))?;
3891
3892 if exec_scope == spirv::Scope::Workgroup as u32
3893 || exec_scope == spirv::Scope::Subgroup as u32
3894 {
3895 let mut flags = crate::Barrier::empty();
3896 flags.set(
3897 crate::Barrier::STORAGE,
3898 semantics & spirv::MemorySemantics::UNIFORM_MEMORY.bits() != 0,
3899 );
3900 flags.set(
3901 crate::Barrier::WORK_GROUP,
3902 semantics & (spirv::MemorySemantics::WORKGROUP_MEMORY).bits() != 0,
3903 );
3904 flags.set(
3905 crate::Barrier::SUB_GROUP,
3906 semantics & spirv::MemorySemantics::SUBGROUP_MEMORY.bits() != 0,
3907 );
3908 flags.set(
3909 crate::Barrier::TEXTURE,
3910 semantics & spirv::MemorySemantics::IMAGE_MEMORY.bits() != 0,
3911 );
3912
3913 block.extend(emitter.finish(ctx.expressions));
3914 block.push(crate::Statement::ControlBarrier(flags), span);
3915 emitter.start(ctx.expressions);
3916 } else {
3917 log::warn!("Unsupported barrier execution scope: {exec_scope}");
3918 }
3919 }
3920 Op::MemoryBarrier => {
3921 inst.expect(3)?;
3922 let mem_scope_id = self.next()?;
3923 let semantics_id = self.next()?;
3924 let mem_scope_const = self.lookup_constant.lookup(mem_scope_id)?;
3925 let semantics_const = self.lookup_constant.lookup(semantics_id)?;
3926
3927 let mem_scope = resolve_constant(ctx.gctx(), &mem_scope_const.inner)
3928 .ok_or(Error::InvalidBarrierScope(mem_scope_id))?;
3929 let semantics = resolve_constant(ctx.gctx(), &semantics_const.inner)
3930 .ok_or(Error::InvalidBarrierMemorySemantics(semantics_id))?;
3931
3932 let mut flags = if mem_scope == spirv::Scope::Device as u32 {
3933 crate::Barrier::STORAGE
3934 } else if mem_scope == spirv::Scope::Workgroup as u32 {
3935 crate::Barrier::WORK_GROUP
3936 } else if mem_scope == spirv::Scope::Subgroup as u32 {
3937 crate::Barrier::SUB_GROUP
3938 } else {
3939 crate::Barrier::empty()
3940 };
3941 flags.set(
3942 crate::Barrier::STORAGE,
3943 semantics & spirv::MemorySemantics::UNIFORM_MEMORY.bits() != 0,
3944 );
3945 flags.set(
3946 crate::Barrier::WORK_GROUP,
3947 semantics & (spirv::MemorySemantics::WORKGROUP_MEMORY).bits() != 0,
3948 );
3949 flags.set(
3950 crate::Barrier::SUB_GROUP,
3951 semantics & spirv::MemorySemantics::SUBGROUP_MEMORY.bits() != 0,
3952 );
3953 flags.set(
3954 crate::Barrier::TEXTURE,
3955 semantics & spirv::MemorySemantics::IMAGE_MEMORY.bits() != 0,
3956 );
3957
3958 block.extend(emitter.finish(ctx.expressions));
3959 block.push(crate::Statement::MemoryBarrier(flags), span);
3960 emitter.start(ctx.expressions);
3961 }
3962 Op::CopyObject => {
3963 inst.expect(4)?;
3964 let result_type_id = self.next()?;
3965 let result_id = self.next()?;
3966 let operand_id = self.next()?;
3967
3968 let lookup = self.lookup_expression.lookup(operand_id)?;
3969 let handle = get_expr_handle!(operand_id, lookup);
3970
3971 self.lookup_expression.insert(
3972 result_id,
3973 LookupExpression {
3974 handle,
3975 type_id: result_type_id,
3976 block_id,
3977 },
3978 );
3979 }
3980 Op::GroupNonUniformBallot => {
3981 inst.expect(5)?;
3982 block.extend(emitter.finish(ctx.expressions));
3983 let result_type_id = self.next()?;
3984 let result_id = self.next()?;
3985 let exec_scope_id = self.next()?;
3986 let predicate_id = self.next()?;
3987
3988 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
3989 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
3990 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
3991 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
3992
3993 let predicate = if self
3994 .lookup_constant
3995 .lookup(predicate_id)
3996 .ok()
3997 .filter(|predicate_const| match predicate_const.inner {
3998 Constant::Constant(constant) => matches!(
3999 ctx.gctx().global_expressions[ctx.gctx().constants[constant].init],
4000 crate::Expression::Literal(crate::Literal::Bool(true)),
4001 ),
4002 Constant::Override(_) => false,
4003 })
4004 .is_some()
4005 {
4006 None
4007 } else {
4008 let predicate_lookup = self.lookup_expression.lookup(predicate_id)?;
4009 let predicate_handle = get_expr_handle!(predicate_id, predicate_lookup);
4010 Some(predicate_handle)
4011 };
4012
4013 let result_handle = ctx
4014 .expressions
4015 .append(crate::Expression::SubgroupBallotResult, span);
4016 self.lookup_expression.insert(
4017 result_id,
4018 LookupExpression {
4019 handle: result_handle,
4020 type_id: result_type_id,
4021 block_id,
4022 },
4023 );
4024
4025 block.push(
4026 crate::Statement::SubgroupBallot {
4027 result: result_handle,
4028 predicate,
4029 },
4030 span,
4031 );
4032 emitter.start(ctx.expressions);
4033 }
4034 Op::GroupNonUniformAll
4035 | Op::GroupNonUniformAny
4036 | Op::GroupNonUniformIAdd
4037 | Op::GroupNonUniformFAdd
4038 | Op::GroupNonUniformIMul
4039 | Op::GroupNonUniformFMul
4040 | Op::GroupNonUniformSMax
4041 | Op::GroupNonUniformUMax
4042 | Op::GroupNonUniformFMax
4043 | Op::GroupNonUniformSMin
4044 | Op::GroupNonUniformUMin
4045 | Op::GroupNonUniformFMin
4046 | Op::GroupNonUniformBitwiseAnd
4047 | Op::GroupNonUniformBitwiseOr
4048 | Op::GroupNonUniformBitwiseXor
4049 | Op::GroupNonUniformLogicalAnd
4050 | Op::GroupNonUniformLogicalOr
4051 | Op::GroupNonUniformLogicalXor => {
4052 block.extend(emitter.finish(ctx.expressions));
4053 inst.expect(
4054 if matches!(inst.op, Op::GroupNonUniformAll | Op::GroupNonUniformAny) {
4055 5
4056 } else {
4057 6
4058 },
4059 )?;
4060 let result_type_id = self.next()?;
4061 let result_id = self.next()?;
4062 let exec_scope_id = self.next()?;
4063 let collective_op_id = match inst.op {
4064 Op::GroupNonUniformAll | Op::GroupNonUniformAny => {
4065 crate::CollectiveOperation::Reduce
4066 }
4067 _ => {
4068 let group_op_id = self.next()?;
4069 match spirv::GroupOperation::from_u32(group_op_id) {
4070 Some(spirv::GroupOperation::Reduce) => {
4071 crate::CollectiveOperation::Reduce
4072 }
4073 Some(spirv::GroupOperation::InclusiveScan) => {
4074 crate::CollectiveOperation::InclusiveScan
4075 }
4076 Some(spirv::GroupOperation::ExclusiveScan) => {
4077 crate::CollectiveOperation::ExclusiveScan
4078 }
4079 _ => return Err(Error::UnsupportedGroupOperation(group_op_id)),
4080 }
4081 }
4082 };
4083 let argument_id = self.next()?;
4084
4085 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
4086 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
4087
4088 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
4089 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
4090 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
4091 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
4092
4093 let op_id = match inst.op {
4094 Op::GroupNonUniformAll => crate::SubgroupOperation::All,
4095 Op::GroupNonUniformAny => crate::SubgroupOperation::Any,
4096 Op::GroupNonUniformIAdd | Op::GroupNonUniformFAdd => {
4097 crate::SubgroupOperation::Add
4098 }
4099 Op::GroupNonUniformIMul | Op::GroupNonUniformFMul => {
4100 crate::SubgroupOperation::Mul
4101 }
4102 Op::GroupNonUniformSMax
4103 | Op::GroupNonUniformUMax
4104 | Op::GroupNonUniformFMax => crate::SubgroupOperation::Max,
4105 Op::GroupNonUniformSMin
4106 | Op::GroupNonUniformUMin
4107 | Op::GroupNonUniformFMin => crate::SubgroupOperation::Min,
4108 Op::GroupNonUniformBitwiseAnd | Op::GroupNonUniformLogicalAnd => {
4109 crate::SubgroupOperation::And
4110 }
4111 Op::GroupNonUniformBitwiseOr | Op::GroupNonUniformLogicalOr => {
4112 crate::SubgroupOperation::Or
4113 }
4114 Op::GroupNonUniformBitwiseXor | Op::GroupNonUniformLogicalXor => {
4115 crate::SubgroupOperation::Xor
4116 }
4117 _ => unreachable!(),
4118 };
4119
4120 let result_type = self.lookup_type.lookup(result_type_id)?;
4121
4122 let result_handle = ctx.expressions.append(
4123 crate::Expression::SubgroupOperationResult {
4124 ty: result_type.handle,
4125 },
4126 span,
4127 );
4128 self.lookup_expression.insert(
4129 result_id,
4130 LookupExpression {
4131 handle: result_handle,
4132 type_id: result_type_id,
4133 block_id,
4134 },
4135 );
4136
4137 block.push(
4138 crate::Statement::SubgroupCollectiveOperation {
4139 result: result_handle,
4140 op: op_id,
4141 collective_op: collective_op_id,
4142 argument: argument_handle,
4143 },
4144 span,
4145 );
4146 emitter.start(ctx.expressions);
4147 }
4148 Op::GroupNonUniformBroadcastFirst
4149 | Op::GroupNonUniformBroadcast
4150 | Op::GroupNonUniformShuffle
4151 | Op::GroupNonUniformShuffleDown
4152 | Op::GroupNonUniformShuffleUp
4153 | Op::GroupNonUniformShuffleXor
4154 | Op::GroupNonUniformQuadBroadcast => {
4155 inst.expect(if matches!(inst.op, Op::GroupNonUniformBroadcastFirst) {
4156 5
4157 } else {
4158 6
4159 })?;
4160 block.extend(emitter.finish(ctx.expressions));
4161 let result_type_id = self.next()?;
4162 let result_id = self.next()?;
4163 let exec_scope_id = self.next()?;
4164 let argument_id = self.next()?;
4165
4166 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
4167 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
4168
4169 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
4170 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
4171 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
4172 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
4173
4174 let mode = if matches!(inst.op, Op::GroupNonUniformBroadcastFirst) {
4175 crate::GatherMode::BroadcastFirst
4176 } else {
4177 let index_id = self.next()?;
4178 let index_lookup = self.lookup_expression.lookup(index_id)?;
4179 let index_handle = get_expr_handle!(index_id, index_lookup);
4180 match inst.op {
4181 Op::GroupNonUniformBroadcast => {
4182 crate::GatherMode::Broadcast(index_handle)
4183 }
4184 Op::GroupNonUniformShuffle => crate::GatherMode::Shuffle(index_handle),
4185 Op::GroupNonUniformShuffleDown => {
4186 crate::GatherMode::ShuffleDown(index_handle)
4187 }
4188 Op::GroupNonUniformShuffleUp => {
4189 crate::GatherMode::ShuffleUp(index_handle)
4190 }
4191 Op::GroupNonUniformShuffleXor => {
4192 crate::GatherMode::ShuffleXor(index_handle)
4193 }
4194 Op::GroupNonUniformQuadBroadcast => {
4195 crate::GatherMode::QuadBroadcast(index_handle)
4196 }
4197 _ => unreachable!(),
4198 }
4199 };
4200
4201 let result_type = self.lookup_type.lookup(result_type_id)?;
4202
4203 let result_handle = ctx.expressions.append(
4204 crate::Expression::SubgroupOperationResult {
4205 ty: result_type.handle,
4206 },
4207 span,
4208 );
4209 self.lookup_expression.insert(
4210 result_id,
4211 LookupExpression {
4212 handle: result_handle,
4213 type_id: result_type_id,
4214 block_id,
4215 },
4216 );
4217
4218 block.push(
4219 crate::Statement::SubgroupGather {
4220 result: result_handle,
4221 mode,
4222 argument: argument_handle,
4223 },
4224 span,
4225 );
4226 emitter.start(ctx.expressions);
4227 }
4228 Op::GroupNonUniformQuadSwap => {
4229 inst.expect(6)?;
4230 block.extend(emitter.finish(ctx.expressions));
4231 let result_type_id = self.next()?;
4232 let result_id = self.next()?;
4233 let exec_scope_id = self.next()?;
4234 let argument_id = self.next()?;
4235 let direction_id = self.next()?;
4236
4237 let argument_lookup = self.lookup_expression.lookup(argument_id)?;
4238 let argument_handle = get_expr_handle!(argument_id, argument_lookup);
4239
4240 let exec_scope_const = self.lookup_constant.lookup(exec_scope_id)?;
4241 let _exec_scope = resolve_constant(ctx.gctx(), &exec_scope_const.inner)
4242 .filter(|exec_scope| *exec_scope == spirv::Scope::Subgroup as u32)
4243 .ok_or(Error::InvalidBarrierScope(exec_scope_id))?;
4244
4245 let direction_const = self.lookup_constant.lookup(direction_id)?;
4246 let direction_const = resolve_constant(ctx.gctx(), &direction_const.inner)
4247 .ok_or(Error::InvalidOperand)?;
4248 let direction = match direction_const {
4249 0 => crate::Direction::X,
4250 1 => crate::Direction::Y,
4251 2 => crate::Direction::Diagonal,
4252 _ => unreachable!(),
4253 };
4254
4255 let result_type = self.lookup_type.lookup(result_type_id)?;
4256
4257 let result_handle = ctx.expressions.append(
4258 crate::Expression::SubgroupOperationResult {
4259 ty: result_type.handle,
4260 },
4261 span,
4262 );
4263 self.lookup_expression.insert(
4264 result_id,
4265 LookupExpression {
4266 handle: result_handle,
4267 type_id: result_type_id,
4268 block_id,
4269 },
4270 );
4271
4272 block.push(
4273 crate::Statement::SubgroupGather {
4274 mode: crate::GatherMode::QuadSwap(direction),
4275 result: result_handle,
4276 argument: argument_handle,
4277 },
4278 span,
4279 );
4280 emitter.start(ctx.expressions);
4281 }
4282 Op::AtomicLoad => {
4283 inst.expect(6)?;
4284 let start = self.data_offset;
4285 let result_type_id = self.next()?;
4286 let result_id = self.next()?;
4287 let pointer_id = self.next()?;
4288 let _scope_id = self.next()?;
4289 let _memory_semantics_id = self.next()?;
4290 let span = self.span_from_with_op(start);
4291
4292 log::trace!("\t\t\tlooking up expr {pointer_id:?}");
4293 let p_lexp_handle =
4294 get_expr_handle!(pointer_id, self.lookup_expression.lookup(pointer_id)?);
4295
4296 let expr = crate::Expression::Load {
4298 pointer: p_lexp_handle,
4299 };
4300 let handle = ctx.expressions.append(expr, span);
4301 self.lookup_expression.insert(
4302 result_id,
4303 LookupExpression {
4304 handle,
4305 type_id: result_type_id,
4306 block_id,
4307 },
4308 );
4309
4310 self.record_atomic_access(ctx, p_lexp_handle)?;
4312 }
4313 Op::AtomicStore => {
4314 inst.expect(5)?;
4315 let start = self.data_offset;
4316 let pointer_id = self.next()?;
4317 let _scope_id = self.next()?;
4318 let _memory_semantics_id = self.next()?;
4319 let value_id = self.next()?;
4320 let span = self.span_from_with_op(start);
4321
4322 log::trace!("\t\t\tlooking up pointer expr {pointer_id:?}");
4323 let p_lexp_handle =
4324 get_expr_handle!(pointer_id, self.lookup_expression.lookup(pointer_id)?);
4325
4326 log::trace!("\t\t\tlooking up value expr {pointer_id:?}");
4327 let v_lexp_handle =
4328 get_expr_handle!(value_id, self.lookup_expression.lookup(value_id)?);
4329
4330 block.extend(emitter.finish(ctx.expressions));
4331 let stmt = crate::Statement::Store {
4333 pointer: p_lexp_handle,
4334 value: v_lexp_handle,
4335 };
4336 block.push(stmt, span);
4337 emitter.start(ctx.expressions);
4338
4339 self.record_atomic_access(ctx, p_lexp_handle)?;
4341 }
4342 Op::AtomicIIncrement | Op::AtomicIDecrement => {
4343 inst.expect(6)?;
4344 let start = self.data_offset;
4345 let result_type_id = self.next()?;
4346 let result_id = self.next()?;
4347 let pointer_id = self.next()?;
4348 let _scope_id = self.next()?;
4349 let _memory_semantics_id = self.next()?;
4350 let span = self.span_from_with_op(start);
4351
4352 let (p_exp_h, p_base_ty_h) = self.get_exp_and_base_ty_handles(
4353 pointer_id,
4354 ctx,
4355 &mut emitter,
4356 &mut block,
4357 body_idx,
4358 )?;
4359
4360 block.extend(emitter.finish(ctx.expressions));
4361 let r_lexp_handle = {
4363 let expr = crate::Expression::AtomicResult {
4364 ty: p_base_ty_h,
4365 comparison: false,
4366 };
4367 let handle = ctx.expressions.append(expr, span);
4368 self.lookup_expression.insert(
4369 result_id,
4370 LookupExpression {
4371 handle,
4372 type_id: result_type_id,
4373 block_id,
4374 },
4375 );
4376 handle
4377 };
4378 emitter.start(ctx.expressions);
4379
4380 let one_lexp_handle = make_index_literal(
4382 ctx,
4383 1,
4384 &mut block,
4385 &mut emitter,
4386 p_base_ty_h,
4387 result_type_id,
4388 span,
4389 )?;
4390
4391 let stmt = crate::Statement::Atomic {
4393 pointer: p_exp_h,
4394 fun: match inst.op {
4395 Op::AtomicIIncrement => crate::AtomicFunction::Add,
4396 _ => crate::AtomicFunction::Subtract,
4397 },
4398 value: one_lexp_handle,
4399 result: Some(r_lexp_handle),
4400 };
4401 block.push(stmt, span);
4402
4403 self.record_atomic_access(ctx, p_exp_h)?;
4405 }
4406 Op::AtomicCompareExchange => {
4407 inst.expect(9)?;
4408
4409 let start = self.data_offset;
4410 let span = self.span_from_with_op(start);
4411 let result_type_id = self.next()?;
4412 let result_id = self.next()?;
4413 let pointer_id = self.next()?;
4414 let _memory_scope_id = self.next()?;
4415 let _equal_memory_semantics_id = self.next()?;
4416 let _unequal_memory_semantics_id = self.next()?;
4417 let value_id = self.next()?;
4418 let comparator_id = self.next()?;
4419
4420 let (p_exp_h, p_base_ty_h) = self.get_exp_and_base_ty_handles(
4421 pointer_id,
4422 ctx,
4423 &mut emitter,
4424 &mut block,
4425 body_idx,
4426 )?;
4427
4428 log::trace!("\t\t\tlooking up value expr {value_id:?}");
4429 let v_lexp_handle =
4430 get_expr_handle!(value_id, self.lookup_expression.lookup(value_id)?);
4431
4432 log::trace!("\t\t\tlooking up comparator expr {value_id:?}");
4433 let c_lexp_handle = get_expr_handle!(
4434 comparator_id,
4435 self.lookup_expression.lookup(comparator_id)?
4436 );
4437
4438 let crate::TypeInner::Scalar(scalar) = ctx.module.types[p_base_ty_h].inner
4442 else {
4443 return Err(
4444 crate::front::atomic_upgrade::Error::CompareExchangeNonScalarBaseType
4445 .into(),
4446 );
4447 };
4448
4449 let atomic_result_struct_ty_h = ctx.module.generate_predeclared_type(
4451 crate::PredeclaredType::AtomicCompareExchangeWeakResult(scalar),
4452 );
4453
4454 block.extend(emitter.finish(ctx.expressions));
4455
4456 let atomic_lexp_handle = {
4458 let expr = crate::Expression::AtomicResult {
4459 ty: atomic_result_struct_ty_h,
4460 comparison: true,
4461 };
4462 ctx.expressions.append(expr, span)
4463 };
4464
4465 {
4469 let expr = crate::Expression::AccessIndex {
4470 base: atomic_lexp_handle,
4471 index: 0,
4472 };
4473 let handle = ctx.expressions.append(expr, span);
4474 let _ = self.lookup_expression.insert(
4476 result_id,
4477 LookupExpression {
4478 handle,
4479 type_id: result_type_id,
4480 block_id,
4481 },
4482 );
4483 }
4484
4485 emitter.start(ctx.expressions);
4486
4487 let stmt = crate::Statement::Atomic {
4489 pointer: p_exp_h,
4490 fun: crate::AtomicFunction::Exchange {
4491 compare: Some(c_lexp_handle),
4492 },
4493 value: v_lexp_handle,
4494 result: Some(atomic_lexp_handle),
4495 };
4496 block.push(stmt, span);
4497
4498 self.record_atomic_access(ctx, p_exp_h)?;
4500 }
4501 Op::AtomicExchange
4502 | Op::AtomicIAdd
4503 | Op::AtomicISub
4504 | Op::AtomicSMin
4505 | Op::AtomicUMin
4506 | Op::AtomicSMax
4507 | Op::AtomicUMax
4508 | Op::AtomicAnd
4509 | Op::AtomicOr
4510 | Op::AtomicXor
4511 | Op::AtomicFAddEXT => self.parse_atomic_expr_with_value(
4512 inst,
4513 &mut emitter,
4514 ctx,
4515 &mut block,
4516 block_id,
4517 body_idx,
4518 match inst.op {
4519 Op::AtomicExchange => crate::AtomicFunction::Exchange { compare: None },
4520 Op::AtomicIAdd | Op::AtomicFAddEXT => crate::AtomicFunction::Add,
4521 Op::AtomicISub => crate::AtomicFunction::Subtract,
4522 Op::AtomicSMin => crate::AtomicFunction::Min,
4523 Op::AtomicUMin => crate::AtomicFunction::Min,
4524 Op::AtomicSMax => crate::AtomicFunction::Max,
4525 Op::AtomicUMax => crate::AtomicFunction::Max,
4526 Op::AtomicAnd => crate::AtomicFunction::And,
4527 Op::AtomicOr => crate::AtomicFunction::InclusiveOr,
4528 Op::AtomicXor => crate::AtomicFunction::ExclusiveOr,
4529 _ => unreachable!(),
4530 },
4531 )?,
4532
4533 _ => {
4534 return Err(Error::UnsupportedInstruction(self.state, inst.op));
4535 }
4536 }
4537 };
4538
4539 block.extend(emitter.finish(ctx.expressions));
4540 if let Some(stmt) = terminator {
4541 block.push(stmt, crate::Span::default());
4542 }
4543
4544 ctx.blocks.insert(block_id, block);
4547 let body = &mut ctx.bodies[body_idx];
4548 body.data.push(BodyFragment::BlockId(block_id));
4549 Ok(())
4550 }
4551
4552 fn make_expression_storage(
4553 &mut self,
4554 globals: &Arena<crate::GlobalVariable>,
4555 constants: &Arena<crate::Constant>,
4556 overrides: &Arena<crate::Override>,
4557 ) -> Arena<crate::Expression> {
4558 let mut expressions = Arena::new();
4559 #[allow(clippy::panic)]
4560 {
4561 assert!(self.lookup_expression.is_empty());
4562 }
4563 for (&id, var) in self.lookup_variable.iter() {
4565 let span = globals.get_span(var.handle);
4566 let handle = expressions.append(crate::Expression::GlobalVariable(var.handle), span);
4567 self.lookup_expression.insert(
4568 id,
4569 LookupExpression {
4570 type_id: var.type_id,
4571 handle,
4572 block_id: 0,
4576 },
4577 );
4578 }
4579 for (&id, con) in self.lookup_constant.iter() {
4581 let (expr, span) = match con.inner {
4582 Constant::Constant(c) => (crate::Expression::Constant(c), constants.get_span(c)),
4583 Constant::Override(o) => (crate::Expression::Override(o), overrides.get_span(o)),
4584 };
4585 let handle = expressions.append(expr, span);
4586 self.lookup_expression.insert(
4587 id,
4588 LookupExpression {
4589 type_id: con.type_id,
4590 handle,
4591 block_id: 0,
4595 },
4596 );
4597 }
4598 expressions
4600 }
4601
4602 fn switch(&mut self, state: ModuleState, op: spirv::Op) -> Result<(), Error> {
4603 if state < self.state {
4604 Err(Error::UnsupportedInstruction(self.state, op))
4605 } else {
4606 self.state = state;
4607 Ok(())
4608 }
4609 }
4610
4611 fn patch_statements(
4614 &mut self,
4615 statements: &mut crate::Block,
4616 expressions: &mut Arena<crate::Expression>,
4617 fun_parameter_sampling: &mut [image::SamplingFlags],
4618 ) -> Result<(), Error> {
4619 use crate::Statement as S;
4620 let mut i = 0usize;
4621 while i < statements.len() {
4622 match statements[i] {
4623 S::Emit(_) => {}
4624 S::Block(ref mut block) => {
4625 self.patch_statements(block, expressions, fun_parameter_sampling)?;
4626 }
4627 S::If {
4628 condition: _,
4629 ref mut accept,
4630 ref mut reject,
4631 } => {
4632 self.patch_statements(reject, expressions, fun_parameter_sampling)?;
4633 self.patch_statements(accept, expressions, fun_parameter_sampling)?;
4634 }
4635 S::Switch {
4636 selector: _,
4637 ref mut cases,
4638 } => {
4639 for case in cases.iter_mut() {
4640 self.patch_statements(&mut case.body, expressions, fun_parameter_sampling)?;
4641 }
4642 }
4643 S::Loop {
4644 ref mut body,
4645 ref mut continuing,
4646 break_if: _,
4647 } => {
4648 self.patch_statements(body, expressions, fun_parameter_sampling)?;
4649 self.patch_statements(continuing, expressions, fun_parameter_sampling)?;
4650 }
4651 S::Break
4652 | S::Continue
4653 | S::Return { .. }
4654 | S::Kill
4655 | S::ControlBarrier(_)
4656 | S::MemoryBarrier(_)
4657 | S::Store { .. }
4658 | S::ImageStore { .. }
4659 | S::Atomic { .. }
4660 | S::ImageAtomic { .. }
4661 | S::RayQuery { .. }
4662 | S::SubgroupBallot { .. }
4663 | S::SubgroupCollectiveOperation { .. }
4664 | S::SubgroupGather { .. } => {}
4665 S::Call {
4666 function: ref mut callee,
4667 ref arguments,
4668 ..
4669 } => {
4670 let fun_id = self.deferred_function_calls[callee.index()];
4671 let fun_lookup = self.lookup_function.lookup(fun_id)?;
4672 *callee = fun_lookup.handle;
4673
4674 for (arg_index, arg) in arguments.iter().enumerate() {
4676 let flags = match fun_lookup.parameters_sampling.get(arg_index) {
4677 Some(&flags) if !flags.is_empty() => flags,
4678 _ => continue,
4679 };
4680
4681 match expressions[*arg] {
4682 crate::Expression::GlobalVariable(handle) => {
4683 if let Some(sampling) = self.handle_sampling.get_mut(&handle) {
4684 *sampling |= flags
4685 }
4686 }
4687 crate::Expression::FunctionArgument(i) => {
4688 fun_parameter_sampling[i as usize] |= flags;
4689 }
4690 ref other => return Err(Error::InvalidGlobalVar(other.clone())),
4691 }
4692 }
4693 }
4694 S::WorkGroupUniformLoad { .. } => unreachable!(),
4695 }
4696 i += 1;
4697 }
4698 Ok(())
4699 }
4700
4701 fn patch_function(
4702 &mut self,
4703 handle: Option<Handle<crate::Function>>,
4704 fun: &mut crate::Function,
4705 ) -> Result<(), Error> {
4706 let (fun_id, mut parameters_sampling) = match handle {
4708 Some(h) => {
4709 let (&fun_id, lookup) = self
4710 .lookup_function
4711 .iter_mut()
4712 .find(|&(_, ref lookup)| lookup.handle == h)
4713 .unwrap();
4714 (fun_id, mem::take(&mut lookup.parameters_sampling))
4715 }
4716 None => (0, Vec::new()),
4717 };
4718
4719 for (_, expr) in fun.expressions.iter_mut() {
4720 if let crate::Expression::CallResult(ref mut function) = *expr {
4721 let fun_id = self.deferred_function_calls[function.index()];
4722 *function = self.lookup_function.lookup(fun_id)?.handle;
4723 }
4724 }
4725
4726 self.patch_statements(
4727 &mut fun.body,
4728 &mut fun.expressions,
4729 &mut parameters_sampling,
4730 )?;
4731
4732 if let Some(lookup) = self.lookup_function.get_mut(&fun_id) {
4733 lookup.parameters_sampling = parameters_sampling;
4734 }
4735 Ok(())
4736 }
4737
4738 pub fn parse(mut self) -> Result<crate::Module, Error> {
4739 let mut module = {
4740 if self.next()? != spirv::MAGIC_NUMBER {
4741 return Err(Error::InvalidHeader);
4742 }
4743 let version_raw = self.next()?;
4744 let generator = self.next()?;
4745 let _bound = self.next()?;
4746 let _schema = self.next()?;
4747 log::info!("Generated by {generator} version {version_raw:x}");
4748 crate::Module::default()
4749 };
4750
4751 self.layouter.clear();
4752 self.dummy_functions = Arena::new();
4753 self.lookup_function.clear();
4754 self.function_call_graph.clear();
4755
4756 loop {
4757 use spirv::Op;
4758
4759 let inst = match self.next_inst() {
4760 Ok(inst) => inst,
4761 Err(Error::IncompleteData) => break,
4762 Err(other) => return Err(other),
4763 };
4764 log::debug!("\t{:?} [{}]", inst.op, inst.wc);
4765
4766 match inst.op {
4767 Op::Capability => self.parse_capability(inst),
4768 Op::Extension => self.parse_extension(inst),
4769 Op::ExtInstImport => self.parse_ext_inst_import(inst),
4770 Op::MemoryModel => self.parse_memory_model(inst),
4771 Op::EntryPoint => self.parse_entry_point(inst),
4772 Op::ExecutionMode => self.parse_execution_mode(inst),
4773 Op::String => self.parse_string(inst),
4774 Op::Source => self.parse_source(inst),
4775 Op::SourceExtension => self.parse_source_extension(inst),
4776 Op::Name => self.parse_name(inst),
4777 Op::MemberName => self.parse_member_name(inst),
4778 Op::ModuleProcessed => self.parse_module_processed(inst),
4779 Op::Decorate => self.parse_decorate(inst),
4780 Op::MemberDecorate => self.parse_member_decorate(inst),
4781 Op::TypeVoid => self.parse_type_void(inst),
4782 Op::TypeBool => self.parse_type_bool(inst, &mut module),
4783 Op::TypeInt => self.parse_type_int(inst, &mut module),
4784 Op::TypeFloat => self.parse_type_float(inst, &mut module),
4785 Op::TypeVector => self.parse_type_vector(inst, &mut module),
4786 Op::TypeMatrix => self.parse_type_matrix(inst, &mut module),
4787 Op::TypeFunction => self.parse_type_function(inst),
4788 Op::TypePointer => self.parse_type_pointer(inst, &mut module),
4789 Op::TypeArray => self.parse_type_array(inst, &mut module),
4790 Op::TypeRuntimeArray => self.parse_type_runtime_array(inst, &mut module),
4791 Op::TypeStruct => self.parse_type_struct(inst, &mut module),
4792 Op::TypeImage => self.parse_type_image(inst, &mut module),
4793 Op::TypeSampledImage => self.parse_type_sampled_image(inst),
4794 Op::TypeSampler => self.parse_type_sampler(inst, &mut module),
4795 Op::Constant | Op::SpecConstant => self.parse_constant(inst, &mut module),
4796 Op::ConstantComposite | Op::SpecConstantComposite => {
4797 self.parse_composite_constant(inst, &mut module)
4798 }
4799 Op::ConstantNull | Op::Undef => self.parse_null_constant(inst, &mut module),
4800 Op::ConstantTrue | Op::SpecConstantTrue => {
4801 self.parse_bool_constant(inst, true, &mut module)
4802 }
4803 Op::ConstantFalse | Op::SpecConstantFalse => {
4804 self.parse_bool_constant(inst, false, &mut module)
4805 }
4806 Op::Variable => self.parse_global_variable(inst, &mut module),
4807 Op::Function => {
4808 self.switch(ModuleState::Function, inst.op)?;
4809 inst.expect(5)?;
4810 self.parse_function(&mut module)
4811 }
4812 _ => Err(Error::UnsupportedInstruction(self.state, inst.op)), }?;
4814 }
4815
4816 if !self.upgrade_atomics.is_empty() {
4817 log::info!("Upgrading atomic pointers...");
4818 module.upgrade_atomics(&self.upgrade_atomics)?;
4819 }
4820
4821 for (ep, fun_id) in mem::take(&mut self.deferred_entry_points) {
4824 self.process_entry_point(&mut module, ep, fun_id)?;
4825 }
4826
4827 log::info!("Patching...");
4828 {
4829 let mut nodes = petgraph::algo::toposort(&self.function_call_graph, None)
4830 .map_err(|cycle| Error::FunctionCallCycle(cycle.node_id()))?;
4831 nodes.reverse(); let mut functions = mem::take(&mut module.functions);
4833 for fun_id in nodes {
4834 if fun_id > !(functions.len() as u32) {
4835 continue;
4837 }
4838 let lookup = self.lookup_function.get_mut(&fun_id).unwrap();
4839 let fun = mem::take(&mut functions[lookup.handle]);
4841 lookup.handle = module
4843 .functions
4844 .append(fun, functions.get_span(lookup.handle));
4845 }
4846 }
4847 for (handle, fun) in module.functions.iter_mut() {
4849 self.patch_function(Some(handle), fun)?;
4850 }
4851 for ep in module.entry_points.iter_mut() {
4852 self.patch_function(None, &mut ep.function)?;
4853 }
4854
4855 for (handle, flags) in self.handle_sampling.drain() {
4857 if !image::patch_comparison_type(
4858 flags,
4859 module.global_variables.get_mut(handle),
4860 &mut module.types,
4861 ) {
4862 return Err(Error::InconsistentComparisonSampling(handle));
4863 }
4864 }
4865
4866 if !self.future_decor.is_empty() {
4867 log::warn!("Unused item decorations: {:?}", self.future_decor);
4868 self.future_decor.clear();
4869 }
4870 if !self.future_member_decor.is_empty() {
4871 log::warn!("Unused member decorations: {:?}", self.future_member_decor);
4872 self.future_member_decor.clear();
4873 }
4874
4875 Ok(module)
4876 }
4877
4878 fn parse_capability(&mut self, inst: Instruction) -> Result<(), Error> {
4879 self.switch(ModuleState::Capability, inst.op)?;
4880 inst.expect(2)?;
4881 let capability = self.next()?;
4882 let cap =
4883 spirv::Capability::from_u32(capability).ok_or(Error::UnknownCapability(capability))?;
4884 if !SUPPORTED_CAPABILITIES.contains(&cap) {
4885 if self.options.strict_capabilities {
4886 return Err(Error::UnsupportedCapability(cap));
4887 } else {
4888 log::warn!("Unknown capability {cap:?}");
4889 }
4890 }
4891 Ok(())
4892 }
4893
4894 fn parse_extension(&mut self, inst: Instruction) -> Result<(), Error> {
4895 self.switch(ModuleState::Extension, inst.op)?;
4896 inst.expect_at_least(2)?;
4897 let (name, left) = self.next_string(inst.wc - 1)?;
4898 if left != 0 {
4899 return Err(Error::InvalidOperand);
4900 }
4901 if !SUPPORTED_EXTENSIONS.contains(&name.as_str()) {
4902 return Err(Error::UnsupportedExtension(name));
4903 }
4904 Ok(())
4905 }
4906
4907 fn parse_ext_inst_import(&mut self, inst: Instruction) -> Result<(), Error> {
4908 self.switch(ModuleState::Extension, inst.op)?;
4909 inst.expect_at_least(3)?;
4910 let result_id = self.next()?;
4911 let (name, left) = self.next_string(inst.wc - 2)?;
4912 if left != 0 {
4913 return Err(Error::InvalidOperand);
4914 }
4915 if !SUPPORTED_EXT_SETS.contains(&name.as_str()) {
4916 return Err(Error::UnsupportedExtSet(name));
4917 }
4918 self.ext_glsl_id = Some(result_id);
4919 Ok(())
4920 }
4921
4922 fn parse_memory_model(&mut self, inst: Instruction) -> Result<(), Error> {
4923 self.switch(ModuleState::MemoryModel, inst.op)?;
4924 inst.expect(3)?;
4925 let _addressing_model = self.next()?;
4926 let _memory_model = self.next()?;
4927 Ok(())
4928 }
4929
4930 fn parse_entry_point(&mut self, inst: Instruction) -> Result<(), Error> {
4931 self.switch(ModuleState::EntryPoint, inst.op)?;
4932 inst.expect_at_least(4)?;
4933 let exec_model = self.next()?;
4934 let exec_model = spirv::ExecutionModel::from_u32(exec_model)
4935 .ok_or(Error::UnsupportedExecutionModel(exec_model))?;
4936 let function_id = self.next()?;
4937 let (name, left) = self.next_string(inst.wc - 3)?;
4938 let ep = EntryPoint {
4939 stage: match exec_model {
4940 spirv::ExecutionModel::Vertex => crate::ShaderStage::Vertex,
4941 spirv::ExecutionModel::Fragment => crate::ShaderStage::Fragment,
4942 spirv::ExecutionModel::GLCompute => crate::ShaderStage::Compute,
4943 _ => return Err(Error::UnsupportedExecutionModel(exec_model as u32)),
4944 },
4945 name,
4946 early_depth_test: None,
4947 workgroup_size: [0; 3],
4948 variable_ids: self.data.by_ref().take(left as usize).collect(),
4949 };
4950 self.lookup_entry_point.insert(function_id, ep);
4951 Ok(())
4952 }
4953
4954 fn parse_execution_mode(&mut self, inst: Instruction) -> Result<(), Error> {
4955 use spirv::ExecutionMode;
4956
4957 self.switch(ModuleState::ExecutionMode, inst.op)?;
4958 inst.expect_at_least(3)?;
4959
4960 let ep_id = self.next()?;
4961 let mode_id = self.next()?;
4962 let args: Vec<spirv::Word> = self.data.by_ref().take(inst.wc as usize - 3).collect();
4963
4964 let ep = self
4965 .lookup_entry_point
4966 .get_mut(&ep_id)
4967 .ok_or(Error::InvalidId(ep_id))?;
4968 let mode =
4969 ExecutionMode::from_u32(mode_id).ok_or(Error::UnsupportedExecutionMode(mode_id))?;
4970
4971 match mode {
4972 ExecutionMode::EarlyFragmentTests => {
4973 ep.early_depth_test = Some(crate::EarlyDepthTest::Force);
4974 }
4975 ExecutionMode::DepthUnchanged => {
4976 if let &mut Some(ref mut early_depth_test) = &mut ep.early_depth_test {
4977 if let &mut crate::EarlyDepthTest::Allow {
4978 ref mut conservative,
4979 } = early_depth_test
4980 {
4981 *conservative = crate::ConservativeDepth::Unchanged;
4982 }
4983 } else {
4984 ep.early_depth_test = Some(crate::EarlyDepthTest::Allow {
4985 conservative: crate::ConservativeDepth::Unchanged,
4986 });
4987 }
4988 }
4989 ExecutionMode::DepthGreater => {
4990 if let &mut Some(ref mut early_depth_test) = &mut ep.early_depth_test {
4991 if let &mut crate::EarlyDepthTest::Allow {
4992 ref mut conservative,
4993 } = early_depth_test
4994 {
4995 *conservative = crate::ConservativeDepth::GreaterEqual;
4996 }
4997 } else {
4998 ep.early_depth_test = Some(crate::EarlyDepthTest::Allow {
4999 conservative: crate::ConservativeDepth::GreaterEqual,
5000 });
5001 }
5002 }
5003 ExecutionMode::DepthLess => {
5004 if let &mut Some(ref mut early_depth_test) = &mut ep.early_depth_test {
5005 if let &mut crate::EarlyDepthTest::Allow {
5006 ref mut conservative,
5007 } = early_depth_test
5008 {
5009 *conservative = crate::ConservativeDepth::LessEqual;
5010 }
5011 } else {
5012 ep.early_depth_test = Some(crate::EarlyDepthTest::Allow {
5013 conservative: crate::ConservativeDepth::LessEqual,
5014 });
5015 }
5016 }
5017 ExecutionMode::DepthReplacing => {
5018 }
5020 ExecutionMode::OriginUpperLeft => {
5021 }
5023 ExecutionMode::LocalSize => {
5024 ep.workgroup_size = [args[0], args[1], args[2]];
5025 }
5026 _ => {
5027 return Err(Error::UnsupportedExecutionMode(mode_id));
5028 }
5029 }
5030
5031 Ok(())
5032 }
5033
5034 fn parse_string(&mut self, inst: Instruction) -> Result<(), Error> {
5035 self.switch(ModuleState::Source, inst.op)?;
5036 inst.expect_at_least(3)?;
5037 let _id = self.next()?;
5038 let (_name, _) = self.next_string(inst.wc - 2)?;
5039 Ok(())
5040 }
5041
5042 fn parse_source(&mut self, inst: Instruction) -> Result<(), Error> {
5043 self.switch(ModuleState::Source, inst.op)?;
5044 for _ in 1..inst.wc {
5045 let _ = self.next()?;
5046 }
5047 Ok(())
5048 }
5049
5050 fn parse_source_extension(&mut self, inst: Instruction) -> Result<(), Error> {
5051 self.switch(ModuleState::Source, inst.op)?;
5052 inst.expect_at_least(2)?;
5053 let (_name, _) = self.next_string(inst.wc - 1)?;
5054 Ok(())
5055 }
5056
5057 fn parse_name(&mut self, inst: Instruction) -> Result<(), Error> {
5058 self.switch(ModuleState::Name, inst.op)?;
5059 inst.expect_at_least(3)?;
5060 let id = self.next()?;
5061 let (name, left) = self.next_string(inst.wc - 2)?;
5062 if left != 0 {
5063 return Err(Error::InvalidOperand);
5064 }
5065 self.future_decor.entry(id).or_default().name = Some(name);
5066 Ok(())
5067 }
5068
5069 fn parse_member_name(&mut self, inst: Instruction) -> Result<(), Error> {
5070 self.switch(ModuleState::Name, inst.op)?;
5071 inst.expect_at_least(4)?;
5072 let id = self.next()?;
5073 let member = self.next()?;
5074 let (name, left) = self.next_string(inst.wc - 3)?;
5075 if left != 0 {
5076 return Err(Error::InvalidOperand);
5077 }
5078
5079 self.future_member_decor
5080 .entry((id, member))
5081 .or_default()
5082 .name = Some(name);
5083 Ok(())
5084 }
5085
5086 fn parse_module_processed(&mut self, inst: Instruction) -> Result<(), Error> {
5087 self.switch(ModuleState::Name, inst.op)?;
5088 inst.expect_at_least(2)?;
5089 let (_info, left) = self.next_string(inst.wc - 1)?;
5090 if left != 0 {
5092 return Err(Error::InvalidOperand);
5093 }
5094 Ok(())
5095 }
5096
5097 fn parse_decorate(&mut self, inst: Instruction) -> Result<(), Error> {
5098 self.switch(ModuleState::Annotation, inst.op)?;
5099 inst.expect_at_least(3)?;
5100 let id = self.next()?;
5101 let mut dec = self.future_decor.remove(&id).unwrap_or_default();
5102 self.next_decoration(inst, 2, &mut dec)?;
5103 self.future_decor.insert(id, dec);
5104 Ok(())
5105 }
5106
5107 fn parse_member_decorate(&mut self, inst: Instruction) -> Result<(), Error> {
5108 self.switch(ModuleState::Annotation, inst.op)?;
5109 inst.expect_at_least(4)?;
5110 let id = self.next()?;
5111 let member = self.next()?;
5112
5113 let mut dec = self
5114 .future_member_decor
5115 .remove(&(id, member))
5116 .unwrap_or_default();
5117 self.next_decoration(inst, 3, &mut dec)?;
5118 self.future_member_decor.insert((id, member), dec);
5119 Ok(())
5120 }
5121
5122 fn parse_type_void(&mut self, inst: Instruction) -> Result<(), Error> {
5123 self.switch(ModuleState::Type, inst.op)?;
5124 inst.expect(2)?;
5125 let id = self.next()?;
5126 self.lookup_void_type = Some(id);
5127 Ok(())
5128 }
5129
5130 fn parse_type_bool(
5131 &mut self,
5132 inst: Instruction,
5133 module: &mut crate::Module,
5134 ) -> Result<(), Error> {
5135 let start = self.data_offset;
5136 self.switch(ModuleState::Type, inst.op)?;
5137 inst.expect(2)?;
5138 let id = self.next()?;
5139 let inner = crate::TypeInner::Scalar(crate::Scalar::BOOL);
5140 self.lookup_type.insert(
5141 id,
5142 LookupType {
5143 handle: module.types.insert(
5144 crate::Type {
5145 name: self.future_decor.remove(&id).and_then(|dec| dec.name),
5146 inner,
5147 },
5148 self.span_from_with_op(start),
5149 ),
5150 base_id: None,
5151 },
5152 );
5153 Ok(())
5154 }
5155
5156 fn parse_type_int(
5157 &mut self,
5158 inst: Instruction,
5159 module: &mut crate::Module,
5160 ) -> Result<(), Error> {
5161 let start = self.data_offset;
5162 self.switch(ModuleState::Type, inst.op)?;
5163 inst.expect(4)?;
5164 let id = self.next()?;
5165 let width = self.next()?;
5166 let sign = self.next()?;
5167 let inner = crate::TypeInner::Scalar(crate::Scalar {
5168 kind: match sign {
5169 0 => crate::ScalarKind::Uint,
5170 1 => crate::ScalarKind::Sint,
5171 _ => return Err(Error::InvalidSign(sign)),
5172 },
5173 width: map_width(width)?,
5174 });
5175 self.lookup_type.insert(
5176 id,
5177 LookupType {
5178 handle: module.types.insert(
5179 crate::Type {
5180 name: self.future_decor.remove(&id).and_then(|dec| dec.name),
5181 inner,
5182 },
5183 self.span_from_with_op(start),
5184 ),
5185 base_id: None,
5186 },
5187 );
5188 Ok(())
5189 }
5190
5191 fn parse_type_float(
5192 &mut self,
5193 inst: Instruction,
5194 module: &mut crate::Module,
5195 ) -> Result<(), Error> {
5196 let start = self.data_offset;
5197 self.switch(ModuleState::Type, inst.op)?;
5198 inst.expect(3)?;
5199 let id = self.next()?;
5200 let width = self.next()?;
5201 let inner = crate::TypeInner::Scalar(crate::Scalar::float(map_width(width)?));
5202 self.lookup_type.insert(
5203 id,
5204 LookupType {
5205 handle: module.types.insert(
5206 crate::Type {
5207 name: self.future_decor.remove(&id).and_then(|dec| dec.name),
5208 inner,
5209 },
5210 self.span_from_with_op(start),
5211 ),
5212 base_id: None,
5213 },
5214 );
5215 Ok(())
5216 }
5217
5218 fn parse_type_vector(
5219 &mut self,
5220 inst: Instruction,
5221 module: &mut crate::Module,
5222 ) -> Result<(), Error> {
5223 let start = self.data_offset;
5224 self.switch(ModuleState::Type, inst.op)?;
5225 inst.expect(4)?;
5226 let id = self.next()?;
5227 let type_id = self.next()?;
5228 let type_lookup = self.lookup_type.lookup(type_id)?;
5229 let scalar = match module.types[type_lookup.handle].inner {
5230 crate::TypeInner::Scalar(scalar) => scalar,
5231 _ => return Err(Error::InvalidInnerType(type_id)),
5232 };
5233 let component_count = self.next()?;
5234 let inner = crate::TypeInner::Vector {
5235 size: map_vector_size(component_count)?,
5236 scalar,
5237 };
5238 self.lookup_type.insert(
5239 id,
5240 LookupType {
5241 handle: module.types.insert(
5242 crate::Type {
5243 name: self.future_decor.remove(&id).and_then(|dec| dec.name),
5244 inner,
5245 },
5246 self.span_from_with_op(start),
5247 ),
5248 base_id: Some(type_id),
5249 },
5250 );
5251 Ok(())
5252 }
5253
5254 fn parse_type_matrix(
5255 &mut self,
5256 inst: Instruction,
5257 module: &mut crate::Module,
5258 ) -> Result<(), Error> {
5259 let start = self.data_offset;
5260 self.switch(ModuleState::Type, inst.op)?;
5261 inst.expect(4)?;
5262 let id = self.next()?;
5263 let vector_type_id = self.next()?;
5264 let num_columns = self.next()?;
5265 let decor = self.future_decor.remove(&id);
5266
5267 let vector_type_lookup = self.lookup_type.lookup(vector_type_id)?;
5268 let inner = match module.types[vector_type_lookup.handle].inner {
5269 crate::TypeInner::Vector { size, scalar } => crate::TypeInner::Matrix {
5270 columns: map_vector_size(num_columns)?,
5271 rows: size,
5272 scalar,
5273 },
5274 _ => return Err(Error::InvalidInnerType(vector_type_id)),
5275 };
5276
5277 self.lookup_type.insert(
5278 id,
5279 LookupType {
5280 handle: module.types.insert(
5281 crate::Type {
5282 name: decor.and_then(|dec| dec.name),
5283 inner,
5284 },
5285 self.span_from_with_op(start),
5286 ),
5287 base_id: Some(vector_type_id),
5288 },
5289 );
5290 Ok(())
5291 }
5292
5293 fn parse_type_function(&mut self, inst: Instruction) -> Result<(), Error> {
5294 self.switch(ModuleState::Type, inst.op)?;
5295 inst.expect_at_least(3)?;
5296 let id = self.next()?;
5297 let return_type_id = self.next()?;
5298 let parameter_type_ids = self.data.by_ref().take(inst.wc as usize - 3).collect();
5299 self.lookup_function_type.insert(
5300 id,
5301 LookupFunctionType {
5302 parameter_type_ids,
5303 return_type_id,
5304 },
5305 );
5306 Ok(())
5307 }
5308
5309 fn parse_type_pointer(
5310 &mut self,
5311 inst: Instruction,
5312 module: &mut crate::Module,
5313 ) -> Result<(), Error> {
5314 let start = self.data_offset;
5315 self.switch(ModuleState::Type, inst.op)?;
5316 inst.expect(4)?;
5317 let id = self.next()?;
5318 let storage_class = self.next()?;
5319 let type_id = self.next()?;
5320
5321 let decor = self.future_decor.remove(&id);
5322 let base_lookup_ty = self.lookup_type.lookup(type_id)?;
5323 let base_inner = &module.types[base_lookup_ty.handle].inner;
5324
5325 let space = if let Some(space) = base_inner.pointer_space() {
5326 space
5327 } else if self
5328 .lookup_storage_buffer_types
5329 .contains_key(&base_lookup_ty.handle)
5330 {
5331 crate::AddressSpace::Storage {
5332 access: crate::StorageAccess::default(),
5333 }
5334 } else {
5335 match map_storage_class(storage_class)? {
5336 ExtendedClass::Global(space) => space,
5337 ExtendedClass::Input | ExtendedClass::Output => crate::AddressSpace::Private,
5338 }
5339 };
5340
5341 if let crate::TypeInner::Array {
5345 size: crate::ArraySize::Dynamic,
5346 ..
5347 } = *base_inner
5348 {
5349 match space {
5350 crate::AddressSpace::Storage { .. } => {}
5351 _ => {
5352 return Err(Error::UnsupportedRuntimeArrayStorageClass);
5353 }
5354 }
5355 }
5356
5357 let lookup_ty = if space == crate::AddressSpace::Handle {
5359 base_lookup_ty.clone()
5360 } else {
5361 LookupType {
5362 handle: module.types.insert(
5363 crate::Type {
5364 name: decor.and_then(|dec| dec.name),
5365 inner: crate::TypeInner::Pointer {
5366 base: base_lookup_ty.handle,
5367 space,
5368 },
5369 },
5370 self.span_from_with_op(start),
5371 ),
5372 base_id: Some(type_id),
5373 }
5374 };
5375 self.lookup_type.insert(id, lookup_ty);
5376 Ok(())
5377 }
5378
5379 fn parse_type_array(
5380 &mut self,
5381 inst: Instruction,
5382 module: &mut crate::Module,
5383 ) -> Result<(), Error> {
5384 let start = self.data_offset;
5385 self.switch(ModuleState::Type, inst.op)?;
5386 inst.expect(4)?;
5387 let id = self.next()?;
5388 let type_id = self.next()?;
5389 let length_id = self.next()?;
5390 let length_const = self.lookup_constant.lookup(length_id)?;
5391
5392 let size = resolve_constant(module.to_ctx(), &length_const.inner)
5393 .and_then(NonZeroU32::new)
5394 .ok_or(Error::InvalidArraySize(length_id))?;
5395
5396 let decor = self.future_decor.remove(&id).unwrap_or_default();
5397 let base = self.lookup_type.lookup(type_id)?.handle;
5398
5399 self.layouter.update(module.to_ctx()).unwrap();
5400
5401 let inner = if let crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } =
5433 module.types[base].inner
5434 {
5435 crate::TypeInner::BindingArray {
5436 base,
5437 size: crate::ArraySize::Constant(size),
5438 }
5439 } else {
5440 crate::TypeInner::Array {
5441 base,
5442 size: crate::ArraySize::Constant(size),
5443 stride: match decor.array_stride {
5444 Some(stride) => stride.get(),
5445 None => self.layouter[base].to_stride(),
5446 },
5447 }
5448 };
5449
5450 self.lookup_type.insert(
5451 id,
5452 LookupType {
5453 handle: module.types.insert(
5454 crate::Type {
5455 name: decor.name,
5456 inner,
5457 },
5458 self.span_from_with_op(start),
5459 ),
5460 base_id: Some(type_id),
5461 },
5462 );
5463 Ok(())
5464 }
5465
5466 fn parse_type_runtime_array(
5467 &mut self,
5468 inst: Instruction,
5469 module: &mut crate::Module,
5470 ) -> Result<(), Error> {
5471 let start = self.data_offset;
5472 self.switch(ModuleState::Type, inst.op)?;
5473 inst.expect(3)?;
5474 let id = self.next()?;
5475 let type_id = self.next()?;
5476
5477 let decor = self.future_decor.remove(&id).unwrap_or_default();
5478 let base = self.lookup_type.lookup(type_id)?.handle;
5479
5480 self.layouter.update(module.to_ctx()).unwrap();
5481
5482 let inner = if let crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } =
5484 module.types[base].inner
5485 {
5486 crate::TypeInner::BindingArray {
5487 base: self.lookup_type.lookup(type_id)?.handle,
5488 size: crate::ArraySize::Dynamic,
5489 }
5490 } else {
5491 crate::TypeInner::Array {
5492 base: self.lookup_type.lookup(type_id)?.handle,
5493 size: crate::ArraySize::Dynamic,
5494 stride: match decor.array_stride {
5495 Some(stride) => stride.get(),
5496 None => self.layouter[base].to_stride(),
5497 },
5498 }
5499 };
5500
5501 self.lookup_type.insert(
5502 id,
5503 LookupType {
5504 handle: module.types.insert(
5505 crate::Type {
5506 name: decor.name,
5507 inner,
5508 },
5509 self.span_from_with_op(start),
5510 ),
5511 base_id: Some(type_id),
5512 },
5513 );
5514 Ok(())
5515 }
5516
5517 fn parse_type_struct(
5518 &mut self,
5519 inst: Instruction,
5520 module: &mut crate::Module,
5521 ) -> Result<(), Error> {
5522 let start = self.data_offset;
5523 self.switch(ModuleState::Type, inst.op)?;
5524 inst.expect_at_least(2)?;
5525 let id = self.next()?;
5526 let parent_decor = self.future_decor.remove(&id);
5527 let is_storage_buffer = parent_decor
5528 .as_ref()
5529 .is_some_and(|decor| decor.storage_buffer);
5530
5531 self.layouter.update(module.to_ctx()).unwrap();
5532
5533 let mut members = Vec::<crate::StructMember>::with_capacity(inst.wc as usize - 2);
5534 let mut member_lookups = Vec::with_capacity(members.capacity());
5535 let mut storage_access = crate::StorageAccess::empty();
5536 let mut span = 0;
5537 let mut alignment = Alignment::ONE;
5538 for i in 0..u32::from(inst.wc) - 2 {
5539 let type_id = self.next()?;
5540 let ty = self.lookup_type.lookup(type_id)?.handle;
5541 let decor = self
5542 .future_member_decor
5543 .remove(&(id, i))
5544 .unwrap_or_default();
5545
5546 storage_access |= decor.flags.to_storage_access();
5547
5548 member_lookups.push(LookupMember {
5549 type_id,
5550 row_major: decor.matrix_major == Some(Majority::Row),
5551 });
5552
5553 let member_alignment = self.layouter[ty].alignment;
5554 span = member_alignment.round_up(span);
5555 alignment = member_alignment.max(alignment);
5556
5557 let binding = decor.io_binding().ok();
5558 if let Some(offset) = decor.offset {
5559 span = offset;
5560 }
5561 let offset = span;
5562
5563 span += self.layouter[ty].size;
5564
5565 let inner = &module.types[ty].inner;
5566 if let crate::TypeInner::Matrix {
5567 columns,
5568 rows,
5569 scalar,
5570 } = *inner
5571 {
5572 if let Some(stride) = decor.matrix_stride {
5573 let expected_stride = Alignment::from(rows) * scalar.width as u32;
5574 if stride.get() != expected_stride {
5575 return Err(Error::UnsupportedMatrixStride {
5576 stride: stride.get(),
5577 columns: columns as u8,
5578 rows: rows as u8,
5579 width: scalar.width,
5580 });
5581 }
5582 }
5583 }
5584
5585 members.push(crate::StructMember {
5586 name: decor.name,
5587 ty,
5588 binding,
5589 offset,
5590 });
5591 }
5592
5593 span = alignment.round_up(span);
5594
5595 let inner = crate::TypeInner::Struct { span, members };
5596
5597 let ty_handle = module.types.insert(
5598 crate::Type {
5599 name: parent_decor.and_then(|dec| dec.name),
5600 inner,
5601 },
5602 self.span_from_with_op(start),
5603 );
5604
5605 if is_storage_buffer {
5606 self.lookup_storage_buffer_types
5607 .insert(ty_handle, storage_access);
5608 }
5609 for (i, member_lookup) in member_lookups.into_iter().enumerate() {
5610 self.lookup_member
5611 .insert((ty_handle, i as u32), member_lookup);
5612 }
5613 self.lookup_type.insert(
5614 id,
5615 LookupType {
5616 handle: ty_handle,
5617 base_id: None,
5618 },
5619 );
5620 Ok(())
5621 }
5622
5623 fn parse_type_image(
5624 &mut self,
5625 inst: Instruction,
5626 module: &mut crate::Module,
5627 ) -> Result<(), Error> {
5628 let start = self.data_offset;
5629 self.switch(ModuleState::Type, inst.op)?;
5630 inst.expect(9)?;
5631
5632 let id = self.next()?;
5633 let sample_type_id = self.next()?;
5634 let dim = self.next()?;
5635 let is_depth = self.next()?;
5636 let is_array = self.next()? != 0;
5637 let is_msaa = self.next()? != 0;
5638 let is_sampled = self.next()?;
5639 let format = self.next()?;
5640
5641 let dim = map_image_dim(dim)?;
5642 let decor = self.future_decor.remove(&id).unwrap_or_default();
5643
5644 module.types.insert(
5646 crate::Type {
5647 name: None,
5648 inner: {
5649 let scalar = crate::Scalar::F32;
5650 match dim.required_coordinate_size() {
5651 None => crate::TypeInner::Scalar(scalar),
5652 Some(size) => crate::TypeInner::Vector { size, scalar },
5653 }
5654 },
5655 },
5656 Default::default(),
5657 );
5658
5659 let base_handle = self.lookup_type.lookup(sample_type_id)?.handle;
5660 let kind = module.types[base_handle]
5661 .inner
5662 .scalar_kind()
5663 .ok_or(Error::InvalidImageBaseType(base_handle))?;
5664
5665 let inner = crate::TypeInner::Image {
5666 class: if is_depth == 1 {
5667 crate::ImageClass::Depth { multi: is_msaa }
5668 } else if format != 0 {
5669 crate::ImageClass::Storage {
5670 format: map_image_format(format)?,
5671 access: crate::StorageAccess::default(),
5672 }
5673 } else if is_sampled == 2 {
5674 return Err(Error::InvalidImageWriteType);
5675 } else {
5676 crate::ImageClass::Sampled {
5677 kind,
5678 multi: is_msaa,
5679 }
5680 },
5681 dim,
5682 arrayed: is_array,
5683 };
5684
5685 let handle = module.types.insert(
5686 crate::Type {
5687 name: decor.name,
5688 inner,
5689 },
5690 self.span_from_with_op(start),
5691 );
5692
5693 self.lookup_type.insert(
5694 id,
5695 LookupType {
5696 handle,
5697 base_id: Some(sample_type_id),
5698 },
5699 );
5700 Ok(())
5701 }
5702
5703 fn parse_type_sampled_image(&mut self, inst: Instruction) -> Result<(), Error> {
5704 self.switch(ModuleState::Type, inst.op)?;
5705 inst.expect(3)?;
5706 let id = self.next()?;
5707 let image_id = self.next()?;
5708 self.lookup_type.insert(
5709 id,
5710 LookupType {
5711 handle: self.lookup_type.lookup(image_id)?.handle,
5712 base_id: Some(image_id),
5713 },
5714 );
5715 Ok(())
5716 }
5717
5718 fn parse_type_sampler(
5719 &mut self,
5720 inst: Instruction,
5721 module: &mut crate::Module,
5722 ) -> Result<(), Error> {
5723 let start = self.data_offset;
5724 self.switch(ModuleState::Type, inst.op)?;
5725 inst.expect(2)?;
5726 let id = self.next()?;
5727 let decor = self.future_decor.remove(&id).unwrap_or_default();
5728 let handle = module.types.insert(
5729 crate::Type {
5730 name: decor.name,
5731 inner: crate::TypeInner::Sampler { comparison: false },
5732 },
5733 self.span_from_with_op(start),
5734 );
5735 self.lookup_type.insert(
5736 id,
5737 LookupType {
5738 handle,
5739 base_id: None,
5740 },
5741 );
5742 Ok(())
5743 }
5744
5745 fn parse_constant(
5746 &mut self,
5747 inst: Instruction,
5748 module: &mut crate::Module,
5749 ) -> Result<(), Error> {
5750 let start = self.data_offset;
5751 self.switch(ModuleState::Type, inst.op)?;
5752 inst.expect_at_least(4)?;
5753 let type_id = self.next()?;
5754 let id = self.next()?;
5755 let type_lookup = self.lookup_type.lookup(type_id)?;
5756 let ty = type_lookup.handle;
5757
5758 let literal = match module.types[ty].inner {
5759 crate::TypeInner::Scalar(crate::Scalar {
5760 kind: crate::ScalarKind::Uint,
5761 width,
5762 }) => {
5763 let low = self.next()?;
5764 match width {
5765 4 => crate::Literal::U32(low),
5766 8 => {
5767 inst.expect(5)?;
5768 let high = self.next()?;
5769 crate::Literal::U64((u64::from(high) << 32) | u64::from(low))
5770 }
5771 _ => return Err(Error::InvalidTypeWidth(width as u32)),
5772 }
5773 }
5774 crate::TypeInner::Scalar(crate::Scalar {
5775 kind: crate::ScalarKind::Sint,
5776 width,
5777 }) => {
5778 let low = self.next()?;
5779 match width {
5780 4 => crate::Literal::I32(low as i32),
5781 8 => {
5782 inst.expect(5)?;
5783 let high = self.next()?;
5784 crate::Literal::I64(((u64::from(high) << 32) | u64::from(low)) as i64)
5785 }
5786 _ => return Err(Error::InvalidTypeWidth(width as u32)),
5787 }
5788 }
5789 crate::TypeInner::Scalar(crate::Scalar {
5790 kind: crate::ScalarKind::Float,
5791 width,
5792 }) => {
5793 let low = self.next()?;
5794 match width {
5795 2 => crate::Literal::F16(f16::from_bits(low as u16)),
5798 4 => crate::Literal::F32(f32::from_bits(low)),
5799 8 => {
5800 inst.expect(5)?;
5801 let high = self.next()?;
5802 crate::Literal::F64(f64::from_bits(
5803 (u64::from(high) << 32) | u64::from(low),
5804 ))
5805 }
5806 _ => return Err(Error::InvalidTypeWidth(width as u32)),
5807 }
5808 }
5809 _ => return Err(Error::UnsupportedType(type_lookup.handle)),
5810 };
5811
5812 let span = self.span_from_with_op(start);
5813
5814 let init = module
5815 .global_expressions
5816 .append(crate::Expression::Literal(literal), span);
5817
5818 self.insert_parsed_constant(module, id, type_id, ty, init, span)
5819 }
5820
5821 fn parse_composite_constant(
5822 &mut self,
5823 inst: Instruction,
5824 module: &mut crate::Module,
5825 ) -> Result<(), Error> {
5826 let start = self.data_offset;
5827 self.switch(ModuleState::Type, inst.op)?;
5828 inst.expect_at_least(3)?;
5829 let type_id = self.next()?;
5830 let id = self.next()?;
5831
5832 let type_lookup = self.lookup_type.lookup(type_id)?;
5833 let ty = type_lookup.handle;
5834
5835 let mut components = Vec::with_capacity(inst.wc as usize - 3);
5836 for _ in 0..components.capacity() {
5837 let start = self.data_offset;
5838 let component_id = self.next()?;
5839 let span = self.span_from_with_op(start);
5840 let constant = self.lookup_constant.lookup(component_id)?;
5841 let expr = module
5842 .global_expressions
5843 .append(constant.inner.to_expr(), span);
5844 components.push(expr);
5845 }
5846
5847 let span = self.span_from_with_op(start);
5848
5849 let init = module
5850 .global_expressions
5851 .append(crate::Expression::Compose { ty, components }, span);
5852
5853 self.insert_parsed_constant(module, id, type_id, ty, init, span)
5854 }
5855
5856 fn parse_null_constant(
5857 &mut self,
5858 inst: Instruction,
5859 module: &mut crate::Module,
5860 ) -> Result<(), Error> {
5861 let start = self.data_offset;
5862 self.switch(ModuleState::Type, inst.op)?;
5863 inst.expect(3)?;
5864 let type_id = self.next()?;
5865 let id = self.next()?;
5866 let span = self.span_from_with_op(start);
5867
5868 let type_lookup = self.lookup_type.lookup(type_id)?;
5869 let ty = type_lookup.handle;
5870
5871 let init = module
5872 .global_expressions
5873 .append(crate::Expression::ZeroValue(ty), span);
5874
5875 self.insert_parsed_constant(module, id, type_id, ty, init, span)
5876 }
5877
5878 fn parse_bool_constant(
5879 &mut self,
5880 inst: Instruction,
5881 value: bool,
5882 module: &mut crate::Module,
5883 ) -> Result<(), Error> {
5884 let start = self.data_offset;
5885 self.switch(ModuleState::Type, inst.op)?;
5886 inst.expect(3)?;
5887 let type_id = self.next()?;
5888 let id = self.next()?;
5889 let span = self.span_from_with_op(start);
5890
5891 let type_lookup = self.lookup_type.lookup(type_id)?;
5892 let ty = type_lookup.handle;
5893
5894 let init = module.global_expressions.append(
5895 crate::Expression::Literal(crate::Literal::Bool(value)),
5896 span,
5897 );
5898
5899 self.insert_parsed_constant(module, id, type_id, ty, init, span)
5900 }
5901
5902 fn insert_parsed_constant(
5903 &mut self,
5904 module: &mut crate::Module,
5905 id: u32,
5906 type_id: u32,
5907 ty: Handle<crate::Type>,
5908 init: Handle<crate::Expression>,
5909 span: crate::Span,
5910 ) -> Result<(), Error> {
5911 let decor = self.future_decor.remove(&id).unwrap_or_default();
5912
5913 let inner = if let Some(id) = decor.specialization_constant_id {
5914 let o = crate::Override {
5915 name: decor.name,
5916 id: Some(id.try_into().map_err(|_| Error::SpecIdTooHigh(id))?),
5917 ty,
5918 init: Some(init),
5919 };
5920 Constant::Override(module.overrides.append(o, span))
5921 } else {
5922 let c = crate::Constant {
5923 name: decor.name,
5924 ty,
5925 init,
5926 };
5927 Constant::Constant(module.constants.append(c, span))
5928 };
5929
5930 self.lookup_constant
5931 .insert(id, LookupConstant { inner, type_id });
5932 Ok(())
5933 }
5934
5935 fn parse_global_variable(
5936 &mut self,
5937 inst: Instruction,
5938 module: &mut crate::Module,
5939 ) -> Result<(), Error> {
5940 let start = self.data_offset;
5941 self.switch(ModuleState::Type, inst.op)?;
5942 inst.expect_at_least(4)?;
5943 let type_id = self.next()?;
5944 let id = self.next()?;
5945 let storage_class = self.next()?;
5946 let init = if inst.wc > 4 {
5947 inst.expect(5)?;
5948 let start = self.data_offset;
5949 let init_id = self.next()?;
5950 let span = self.span_from_with_op(start);
5951 let lconst = self.lookup_constant.lookup(init_id)?;
5952 let expr = module
5953 .global_expressions
5954 .append(lconst.inner.to_expr(), span);
5955 Some(expr)
5956 } else {
5957 None
5958 };
5959 let span = self.span_from_with_op(start);
5960 let dec = self.future_decor.remove(&id).unwrap_or_default();
5961
5962 let original_ty = self.lookup_type.lookup(type_id)?.handle;
5963 let mut ty = original_ty;
5964
5965 if let crate::TypeInner::Pointer { base, space: _ } = module.types[original_ty].inner {
5966 ty = base;
5967 }
5968
5969 if let crate::TypeInner::BindingArray { .. } = module.types[original_ty].inner {
5970 if dec.desc_set.is_none() || dec.desc_index.is_none() {
5973 return Err(Error::NonBindingArrayOfImageOrSamplers);
5974 }
5975 }
5976
5977 if let crate::TypeInner::Image {
5978 dim,
5979 arrayed,
5980 class: crate::ImageClass::Storage { format, access: _ },
5981 } = module.types[ty].inner
5982 {
5983 let access = dec.flags.to_storage_access();
5987
5988 ty = module.types.insert(
5989 crate::Type {
5990 name: None,
5991 inner: crate::TypeInner::Image {
5992 dim,
5993 arrayed,
5994 class: crate::ImageClass::Storage { format, access },
5995 },
5996 },
5997 Default::default(),
5998 );
5999 }
6000
6001 let ext_class = match self.lookup_storage_buffer_types.get(&ty) {
6002 Some(&access) => ExtendedClass::Global(crate::AddressSpace::Storage { access }),
6003 None => map_storage_class(storage_class)?,
6004 };
6005
6006 let (inner, var) = match ext_class {
6007 ExtendedClass::Global(mut space) => {
6008 if let crate::AddressSpace::Storage { ref mut access } = space {
6009 *access &= dec.flags.to_storage_access();
6010 }
6011 let var = crate::GlobalVariable {
6012 binding: dec.resource_binding(),
6013 name: dec.name,
6014 space,
6015 ty,
6016 init,
6017 };
6018 (Variable::Global, var)
6019 }
6020 ExtendedClass::Input => {
6021 let binding = dec.io_binding()?;
6022 let mut unsigned_ty = ty;
6023 if let crate::Binding::BuiltIn(built_in) = binding {
6024 let needs_inner_uint = match built_in {
6025 crate::BuiltIn::BaseInstance
6026 | crate::BuiltIn::BaseVertex
6027 | crate::BuiltIn::InstanceIndex
6028 | crate::BuiltIn::SampleIndex
6029 | crate::BuiltIn::VertexIndex
6030 | crate::BuiltIn::PrimitiveIndex
6031 | crate::BuiltIn::LocalInvocationIndex => {
6032 Some(crate::TypeInner::Scalar(crate::Scalar::U32))
6033 }
6034 crate::BuiltIn::GlobalInvocationId
6035 | crate::BuiltIn::LocalInvocationId
6036 | crate::BuiltIn::WorkGroupId
6037 | crate::BuiltIn::WorkGroupSize => Some(crate::TypeInner::Vector {
6038 size: crate::VectorSize::Tri,
6039 scalar: crate::Scalar::U32,
6040 }),
6041 _ => None,
6042 };
6043 if let (Some(inner), Some(crate::ScalarKind::Sint)) =
6044 (needs_inner_uint, module.types[ty].inner.scalar_kind())
6045 {
6046 unsigned_ty = module
6047 .types
6048 .insert(crate::Type { name: None, inner }, Default::default());
6049 }
6050 }
6051
6052 let var = crate::GlobalVariable {
6053 name: dec.name.clone(),
6054 space: crate::AddressSpace::Private,
6055 binding: None,
6056 ty,
6057 init: None,
6058 };
6059
6060 let inner = Variable::Input(crate::FunctionArgument {
6061 name: dec.name,
6062 ty: unsigned_ty,
6063 binding: Some(binding),
6064 });
6065 (inner, var)
6066 }
6067 ExtendedClass::Output => {
6068 let binding = dec.io_binding().ok();
6070 let init = match binding {
6071 Some(crate::Binding::BuiltIn(built_in)) => {
6072 match null::generate_default_built_in(
6073 Some(built_in),
6074 ty,
6075 &mut module.global_expressions,
6076 span,
6077 ) {
6078 Ok(handle) => Some(handle),
6079 Err(e) => {
6080 log::warn!("Failed to initialize output built-in: {e}");
6081 None
6082 }
6083 }
6084 }
6085 Some(crate::Binding::Location { .. }) => None,
6086 None => match module.types[ty].inner {
6087 crate::TypeInner::Struct { ref members, .. } => {
6088 let mut components = Vec::with_capacity(members.len());
6089 for member in members.iter() {
6090 let built_in = match member.binding {
6091 Some(crate::Binding::BuiltIn(built_in)) => Some(built_in),
6092 _ => None,
6093 };
6094 let handle = null::generate_default_built_in(
6095 built_in,
6096 member.ty,
6097 &mut module.global_expressions,
6098 span,
6099 )?;
6100 components.push(handle);
6101 }
6102 Some(
6103 module
6104 .global_expressions
6105 .append(crate::Expression::Compose { ty, components }, span),
6106 )
6107 }
6108 _ => None,
6109 },
6110 };
6111
6112 let var = crate::GlobalVariable {
6113 name: dec.name,
6114 space: crate::AddressSpace::Private,
6115 binding: None,
6116 ty,
6117 init,
6118 };
6119 let inner = Variable::Output(crate::FunctionResult { ty, binding });
6120 (inner, var)
6121 }
6122 };
6123
6124 let handle = module.global_variables.append(var, span);
6125
6126 if module.types[ty].inner.can_comparison_sample(module) {
6127 log::debug!("\t\ttracking {handle:?} for sampling properties");
6128
6129 self.handle_sampling
6130 .insert(handle, image::SamplingFlags::empty());
6131 }
6132
6133 self.lookup_variable.insert(
6134 id,
6135 LookupVariable {
6136 inner,
6137 handle,
6138 type_id,
6139 },
6140 );
6141 Ok(())
6142 }
6143
6144 fn record_atomic_access(
6157 &mut self,
6158 ctx: &BlockContext,
6159 handle: Handle<crate::Expression>,
6160 ) -> Result<Handle<crate::Type>, Error> {
6161 log::debug!("\t\tlocating global variable in {handle:?}");
6162 match ctx.expressions[handle] {
6163 crate::Expression::Access { base, index } => {
6164 log::debug!("\t\t access {handle:?} {index:?}");
6165 let ty = self.record_atomic_access(ctx, base)?;
6166 let crate::TypeInner::Array { base, .. } = ctx.module.types[ty].inner else {
6167 unreachable!("Atomic operations on Access expressions only work for arrays");
6168 };
6169 Ok(base)
6170 }
6171 crate::Expression::AccessIndex { base, index } => {
6172 log::debug!("\t\t access index {handle:?} {index:?}");
6173 let ty = self.record_atomic_access(ctx, base)?;
6174 match ctx.module.types[ty].inner {
6175 crate::TypeInner::Struct { ref members, .. } => {
6176 let index = index as usize;
6177 self.upgrade_atomics.insert_field(ty, index);
6178 Ok(members[index].ty)
6179 }
6180 crate::TypeInner::Array { base, .. } => {
6181 Ok(base)
6182 }
6183 _ => unreachable!("Atomic operations on AccessIndex expressions only work for structs and arrays"),
6184 }
6185 }
6186 crate::Expression::GlobalVariable(h) => {
6187 log::debug!("\t\t found {h:?}");
6188 self.upgrade_atomics.insert_global(h);
6189 Ok(ctx.module.global_variables[h].ty)
6190 }
6191 _ => Err(Error::AtomicUpgradeError(
6192 crate::front::atomic_upgrade::Error::GlobalVariableMissing,
6193 )),
6194 }
6195 }
6196}
6197
6198fn make_index_literal(
6199 ctx: &mut BlockContext,
6200 index: u32,
6201 block: &mut crate::Block,
6202 emitter: &mut crate::proc::Emitter,
6203 index_type: Handle<crate::Type>,
6204 index_type_id: spirv::Word,
6205 span: crate::Span,
6206) -> Result<Handle<crate::Expression>, Error> {
6207 block.extend(emitter.finish(ctx.expressions));
6208
6209 let literal = match ctx.module.types[index_type].inner.scalar_kind() {
6210 Some(crate::ScalarKind::Uint) => crate::Literal::U32(index),
6211 Some(crate::ScalarKind::Sint) => crate::Literal::I32(index as i32),
6212 _ => return Err(Error::InvalidIndexType(index_type_id)),
6213 };
6214 let expr = ctx
6215 .expressions
6216 .append(crate::Expression::Literal(literal), span);
6217
6218 emitter.start(ctx.expressions);
6219 Ok(expr)
6220}
6221
6222fn resolve_constant(gctx: crate::proc::GlobalCtx, constant: &Constant) -> Option<u32> {
6223 let constant = match *constant {
6224 Constant::Constant(constant) => constant,
6225 Constant::Override(_) => return None,
6226 };
6227 match gctx.global_expressions[gctx.constants[constant].init] {
6228 crate::Expression::Literal(crate::Literal::U32(id)) => Some(id),
6229 crate::Expression::Literal(crate::Literal::I32(id)) => Some(id as u32),
6230 _ => None,
6231 }
6232}
6233
6234pub fn parse_u8_slice(data: &[u8], options: &Options) -> Result<crate::Module, Error> {
6235 if data.len() % 4 != 0 {
6236 return Err(Error::IncompleteData);
6237 }
6238
6239 let words = data
6240 .chunks(4)
6241 .map(|c| u32::from_le_bytes(c.try_into().unwrap()));
6242 Frontend::new(words, options).parse()
6243}
6244
6245fn is_parent(mut child: usize, parent: usize, block_ctx: &BlockContext) -> bool {
6247 loop {
6248 if child == parent {
6249 break true;
6251 } else if child == 0 {
6252 break false;
6254 }
6255
6256 child = block_ctx.bodies[child].parent;
6257 }
6258}
6259
6260#[cfg(test)]
6261mod test {
6262 use alloc::vec;
6263
6264 #[test]
6265 fn parse() {
6266 let bin = vec![
6267 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00,
6269 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6274 ];
6275 let _ = super::parse_u8_slice(&bin, &Default::default()).unwrap();
6276 }
6277}