1mod convert;
31mod error;
32mod function;
33mod image;
34mod next_block;
35mod null;
36
37pub use error::Error;
38
39use alloc::{borrow::ToOwned, string::String, vec, vec::Vec};
40use core::{convert::TryInto, mem, num::NonZeroU32};
41
42use half::f16;
43use petgraph::graphmap::GraphMap;
44
45use super::atomic_upgrade::Upgrades;
46use crate::{
47 arena::{Arena, Handle, UniqueArena},
48 proc::{Alignment, Layouter},
49 FastHashMap, FastHashSet, FastIndexMap,
50};
51use convert::*;
52use function::*;
53
54pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[
55 spirv::Capability::Shader,
56 spirv::Capability::VulkanMemoryModel,
57 spirv::Capability::ClipDistance,
58 spirv::Capability::CullDistance,
59 spirv::Capability::SampleRateShading,
60 spirv::Capability::DerivativeControl,
61 spirv::Capability::Matrix,
62 spirv::Capability::ImageQuery,
63 spirv::Capability::Sampled1D,
64 spirv::Capability::Image1D,
65 spirv::Capability::SampledCubeArray,
66 spirv::Capability::ImageCubeArray,
67 spirv::Capability::StorageImageExtendedFormats,
68 spirv::Capability::Int8,
69 spirv::Capability::Int16,
70 spirv::Capability::Int64,
71 spirv::Capability::Int64Atomics,
72 spirv::Capability::Float16,
73 spirv::Capability::AtomicFloat32AddEXT,
74 spirv::Capability::Float64,
75 spirv::Capability::Geometry,
76 spirv::Capability::MultiView,
77 spirv::Capability::StorageBuffer16BitAccess,
78 spirv::Capability::UniformAndStorageBuffer16BitAccess,
79 spirv::Capability::GroupNonUniform,
80 spirv::Capability::GroupNonUniformVote,
81 spirv::Capability::GroupNonUniformArithmetic,
82 spirv::Capability::GroupNonUniformBallot,
83 spirv::Capability::GroupNonUniformShuffle,
84 spirv::Capability::GroupNonUniformShuffleRelative,
85 spirv::Capability::RuntimeDescriptorArray,
86 spirv::Capability::StorageImageMultisample,
87 spirv::Capability::FragmentBarycentricKHR,
88 spirv::Capability::UniformBufferArrayDynamicIndexing,
90 spirv::Capability::StorageBufferArrayDynamicIndexing,
91];
92pub const SUPPORTED_EXTENSIONS: &[&str] = &[
93 "SPV_KHR_storage_buffer_storage_class",
94 "SPV_KHR_vulkan_memory_model",
95 "SPV_KHR_multiview",
96 "SPV_EXT_descriptor_indexing",
97 "SPV_EXT_shader_atomic_float_add",
98 "SPV_KHR_16bit_storage",
99 "SPV_KHR_non_semantic_info",
100 "SPV_KHR_fragment_shader_barycentric",
101];
102
103#[derive(Copy, Clone)]
104pub struct Instruction {
105 op: spirv::Op,
106 wc: u16,
107}
108
109impl Instruction {
110 const fn expect(self, count: u16) -> Result<(), Error> {
111 if self.wc == count {
112 Ok(())
113 } else {
114 Err(Error::InvalidOperandCount(self.op, self.wc))
115 }
116 }
117
118 fn expect_at_least(self, count: u16) -> Result<u16, Error> {
119 self.wc
120 .checked_sub(count)
121 .ok_or(Error::InvalidOperandCount(self.op, self.wc))
122 }
123}
124
125impl crate::TypeInner {
126 fn can_comparison_sample(&self, module: &crate::Module) -> bool {
127 match *self {
128 crate::TypeInner::Image {
129 class:
130 crate::ImageClass::Sampled {
131 kind: crate::ScalarKind::Float,
132 multi: false,
133 },
134 ..
135 } => true,
136 crate::TypeInner::Sampler { .. } => true,
137 crate::TypeInner::BindingArray { base, .. } => {
138 module.types[base].inner.can_comparison_sample(module)
139 }
140 _ => false,
141 }
142 }
143}
144
145#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
146pub enum ModuleState {
147 Empty,
148 Capability,
149 Extension,
150 ExtInstImport,
151 MemoryModel,
152 EntryPoint,
153 ExecutionMode,
154 Source,
155 Name,
156 ModuleProcessed,
157 Annotation,
158 Type,
159 Function,
160}
161
162trait LookupHelper {
163 type Target;
164 fn lookup(&self, key: spirv::Word) -> Result<&Self::Target, Error>;
165}
166
167impl<T> LookupHelper for FastHashMap<spirv::Word, T> {
168 type Target = T;
169 fn lookup(&self, key: spirv::Word) -> Result<&T, Error> {
170 self.get(&key).ok_or(Error::InvalidId(key))
171 }
172}
173
174impl crate::ImageDimension {
175 const fn required_coordinate_size(&self) -> Option<crate::VectorSize> {
176 match *self {
177 crate::ImageDimension::D1 => None,
178 crate::ImageDimension::D2 => Some(crate::VectorSize::Bi),
179 crate::ImageDimension::D3 => Some(crate::VectorSize::Tri),
180 crate::ImageDimension::Cube => Some(crate::VectorSize::Tri),
181 }
182 }
183}
184
185type MemberIndex = u32;
186
187bitflags::bitflags! {
188 #[derive(Clone, Copy, Debug, Default)]
189 struct DecorationFlags: u32 {
190 const NON_READABLE = 0x1;
191 const NON_WRITABLE = 0x2;
192 }
193}
194
195impl DecorationFlags {
196 fn to_storage_access(self) -> crate::StorageAccess {
197 let mut access = crate::StorageAccess::LOAD | crate::StorageAccess::STORE;
198 if self.contains(DecorationFlags::NON_READABLE) {
199 access &= !crate::StorageAccess::LOAD;
200 }
201 if self.contains(DecorationFlags::NON_WRITABLE) {
202 access &= !crate::StorageAccess::STORE;
203 }
204 access
205 }
206}
207
208#[derive(Debug, PartialEq)]
209enum Majority {
210 Column,
211 Row,
212}
213
214#[derive(Debug, Default)]
215struct Decoration {
216 name: Option<String>,
217 built_in: Option<spirv::Word>,
218 location: Option<spirv::Word>,
219 desc_set: Option<spirv::Word>,
220 desc_index: Option<spirv::Word>,
221 specialization_constant_id: Option<spirv::Word>,
222 storage_buffer: bool,
223 offset: Option<spirv::Word>,
224 array_stride: Option<NonZeroU32>,
225 matrix_stride: Option<NonZeroU32>,
226 matrix_major: Option<Majority>,
227 invariant: bool,
228 interpolation: Option<crate::Interpolation>,
229 sampling: Option<crate::Sampling>,
230 flags: DecorationFlags,
231}
232
233impl Decoration {
234 fn debug_name(&self) -> &str {
235 match self.name {
236 Some(ref name) => name.as_str(),
237 None => "?",
238 }
239 }
240
241 const fn resource_binding(&self) -> Option<crate::ResourceBinding> {
242 match *self {
243 Decoration {
244 desc_set: Some(group),
245 desc_index: Some(binding),
246 ..
247 } => Some(crate::ResourceBinding { group, binding }),
248 _ => None,
249 }
250 }
251
252 fn io_binding(&self) -> Result<crate::Binding, Error> {
253 match *self {
254 Decoration {
255 built_in: Some(built_in),
256 location: None,
257 invariant,
258 ..
259 } => Ok(crate::Binding::BuiltIn(map_builtin(built_in, invariant)?)),
260 Decoration {
261 built_in: None,
262 location: Some(location),
263 interpolation,
264 sampling,
265 ..
266 } => Ok(crate::Binding::Location {
267 location,
268 interpolation,
269 sampling,
270 blend_src: None,
271 per_primitive: false,
272 }),
273 _ => Err(Error::MissingDecoration(spirv::Decoration::Location)),
274 }
275 }
276}
277
278#[derive(Debug)]
279struct LookupFunctionType {
280 parameter_type_ids: Vec<spirv::Word>,
281 return_type_id: spirv::Word,
282}
283
284struct LookupFunction {
285 handle: Handle<crate::Function>,
286 parameters_sampling: Vec<image::SamplingFlags>,
287}
288
289#[derive(Debug)]
290struct EntryPoint {
291 stage: crate::ShaderStage,
292 name: String,
293 early_depth_test: Option<crate::EarlyDepthTest>,
294 workgroup_size: [u32; 3],
295 variable_ids: Vec<spirv::Word>,
296}
297
298#[derive(Clone, Debug)]
299struct LookupType {
300 handle: Handle<crate::Type>,
301 base_id: Option<spirv::Word>,
302}
303
304#[derive(Debug)]
305enum Constant {
306 Constant(Handle<crate::Constant>),
307 Override(Handle<crate::Override>),
308}
309
310impl Constant {
311 const fn to_expr(&self) -> crate::Expression {
312 match *self {
313 Self::Constant(c) => crate::Expression::Constant(c),
314 Self::Override(o) => crate::Expression::Override(o),
315 }
316 }
317}
318
319#[derive(Debug)]
320struct LookupConstant {
321 inner: Constant,
322 type_id: spirv::Word,
323}
324
325#[derive(Debug)]
326enum Variable {
327 Global,
328 Input(crate::FunctionArgument),
329 Output(crate::FunctionResult),
330}
331
332#[derive(Debug)]
333struct LookupVariable {
334 inner: Variable,
335 handle: Handle<crate::GlobalVariable>,
336 type_id: spirv::Word,
337}
338
339#[derive(Clone, Debug)]
341struct LookupExpression {
342 handle: Handle<crate::Expression>,
349
350 type_id: spirv::Word,
352
353 block_id: spirv::Word,
358}
359
360#[derive(Debug)]
361struct LookupMember {
362 type_id: spirv::Word,
363 row_major: bool,
365}
366
367#[derive(Clone, Debug)]
368enum LookupLoadOverride {
369 Pending,
371 Loaded(Handle<crate::Expression>),
373}
374
375#[derive(PartialEq)]
376enum ExtendedClass {
377 Global(crate::AddressSpace),
378 Input,
379 Output,
380}
381
382#[derive(Clone, Debug)]
383pub struct Options {
384 pub adjust_coordinate_space: bool,
388 pub strict_capabilities: bool,
390 pub block_ctx_dump_prefix: Option<String>,
391}
392
393impl Default for Options {
394 fn default() -> Self {
395 Options {
396 adjust_coordinate_space: true,
397 strict_capabilities: true,
398 block_ctx_dump_prefix: None,
399 }
400 }
401}
402
403type BodyIndex = usize;
405
406#[derive(Debug)]
415enum BodyFragment {
416 BlockId(spirv::Word),
417 If {
418 condition: Handle<crate::Expression>,
419 accept: BodyIndex,
420 reject: BodyIndex,
421 },
422 Loop {
423 body: BodyIndex,
426
427 continuing: BodyIndex,
430
431 break_if: Option<Handle<crate::Expression>>,
435 },
436 Switch {
437 selector: Handle<crate::Expression>,
438 cases: Vec<(i32, BodyIndex)>,
439 default: BodyIndex,
440 },
441 Break,
442 Continue,
443}
444
445#[derive(Debug)]
452struct Body {
453 parent: usize,
455 data: Vec<BodyFragment>,
456}
457
458impl Body {
459 pub const fn with_parent(parent: usize) -> Self {
461 Body {
462 parent,
463 data: Vec::new(),
464 }
465 }
466}
467
468#[derive(Debug)]
469struct PhiExpression {
470 local: Handle<crate::LocalVariable>,
472 expressions: Vec<(spirv::Word, spirv::Word)>,
474}
475
476#[derive(Copy, Clone, Debug, PartialEq, Eq)]
477enum MergeBlockInformation {
478 LoopMerge,
479 LoopContinue,
480 SelectionMerge,
481 SwitchMerge,
482}
483
484#[derive(Debug)]
525struct BlockContext<'function> {
526 phis: Vec<PhiExpression>,
529
530 blocks: FastHashMap<spirv::Word, crate::Block>,
537
538 body_for_label: FastHashMap<spirv::Word, BodyIndex>,
556
557 mergers: FastHashMap<spirv::Word, MergeBlockInformation>,
559
560 bodies: Vec<Body>,
564
565 module: &'function mut crate::Module,
567
568 function_id: spirv::Word,
570 expressions: &'function mut Arena<crate::Expression>,
572 local_arena: &'function mut Arena<crate::LocalVariable>,
574 arguments: &'function [crate::FunctionArgument],
576 parameter_sampling: &'function mut [image::SamplingFlags],
578}
579
580enum SignAnchor {
581 Result,
582 Operand,
583}
584
585pub struct Frontend<I> {
586 data: I,
587 data_offset: usize,
588 state: ModuleState,
589 layouter: Layouter,
590 temp_bytes: Vec<u8>,
591 ext_glsl_id: Option<spirv::Word>,
592 ext_non_semantic_id: Option<spirv::Word>,
593 future_decor: FastHashMap<spirv::Word, Decoration>,
594 future_member_decor: FastHashMap<(spirv::Word, MemberIndex), Decoration>,
595 lookup_member: FastHashMap<(Handle<crate::Type>, MemberIndex), LookupMember>,
596 handle_sampling: FastHashMap<Handle<crate::GlobalVariable>, image::SamplingFlags>,
597
598 upgrade_atomics: Upgrades,
603
604 lookup_type: FastHashMap<spirv::Word, LookupType>,
605 lookup_void_type: Option<spirv::Word>,
606 lookup_storage_buffer_types: FastHashMap<Handle<crate::Type>, crate::StorageAccess>,
607 lookup_constant: FastHashMap<spirv::Word, LookupConstant>,
608 lookup_variable: FastHashMap<spirv::Word, LookupVariable>,
609 lookup_expression: FastHashMap<spirv::Word, LookupExpression>,
610 lookup_load_override: FastHashMap<spirv::Word, LookupLoadOverride>,
612 lookup_sampled_image: FastHashMap<spirv::Word, image::LookupSampledImage>,
613 lookup_function_type: FastHashMap<spirv::Word, LookupFunctionType>,
614 lookup_function: FastHashMap<spirv::Word, LookupFunction>,
615 lookup_entry_point: FastHashMap<spirv::Word, EntryPoint>,
616 deferred_entry_points: Vec<(EntryPoint, spirv::Word)>,
619 deferred_function_calls: Vec<spirv::Word>,
622 dummy_functions: Arena<crate::Function>,
623 function_call_graph: GraphMap<
627 spirv::Word,
628 (),
629 petgraph::Directed,
630 core::hash::BuildHasherDefault<rustc_hash::FxHasher>,
631 >,
632 options: Options,
633
634 switch_cases: FastIndexMap<spirv::Word, (BodyIndex, Vec<i32>)>,
639
640 gl_per_vertex_builtin_access: FastHashSet<crate::BuiltIn>,
649}
650
651impl<I: Iterator<Item = u32>> Frontend<I> {
652 pub fn new(data: I, options: &Options) -> Self {
653 Frontend {
654 data,
655 data_offset: 0,
656 state: ModuleState::Empty,
657 layouter: Layouter::default(),
658 temp_bytes: Vec::new(),
659 ext_glsl_id: None,
660 ext_non_semantic_id: None,
661 future_decor: FastHashMap::default(),
662 future_member_decor: FastHashMap::default(),
663 handle_sampling: FastHashMap::default(),
664 lookup_member: FastHashMap::default(),
665 upgrade_atomics: Default::default(),
666 lookup_type: FastHashMap::default(),
667 lookup_void_type: None,
668 lookup_storage_buffer_types: FastHashMap::default(),
669 lookup_constant: FastHashMap::default(),
670 lookup_variable: FastHashMap::default(),
671 lookup_expression: FastHashMap::default(),
672 lookup_load_override: FastHashMap::default(),
673 lookup_sampled_image: FastHashMap::default(),
674 lookup_function_type: FastHashMap::default(),
675 lookup_function: FastHashMap::default(),
676 lookup_entry_point: FastHashMap::default(),
677 deferred_entry_points: Vec::default(),
678 deferred_function_calls: Vec::default(),
679 dummy_functions: Arena::new(),
680 function_call_graph: GraphMap::new(),
681 options: options.clone(),
682 switch_cases: FastIndexMap::default(),
683 gl_per_vertex_builtin_access: FastHashSet::default(),
684 }
685 }
686
687 fn span_from(&self, from: usize) -> crate::Span {
688 crate::Span::from(from..self.data_offset)
689 }
690
691 fn span_from_with_op(&self, from: usize) -> crate::Span {
692 crate::Span::from((from - 4)..self.data_offset)
693 }
694
695 fn next(&mut self) -> Result<u32, Error> {
696 if let Some(res) = self.data.next() {
697 self.data_offset += 4;
698 Ok(res)
699 } else {
700 Err(Error::IncompleteData)
701 }
702 }
703
704 fn next_inst(&mut self) -> Result<Instruction, Error> {
705 let word = self.next()?;
706 let (wc, opcode) = ((word >> 16) as u16, (word & 0xffff) as u16);
707 if wc == 0 {
708 return Err(Error::InvalidWordCount);
709 }
710 let op = spirv::Op::from_u32(opcode as u32).ok_or(Error::UnknownInstruction(opcode))?;
711
712 Ok(Instruction { op, wc })
713 }
714
715 fn next_string(&mut self, mut count: u16) -> Result<(String, u16), Error> {
716 self.temp_bytes.clear();
717 loop {
718 if count == 0 {
719 return Err(Error::BadString);
720 }
721 count -= 1;
722 let chars = self.next()?.to_le_bytes();
723 let pos = chars.iter().position(|&c| c == 0).unwrap_or(4);
724 self.temp_bytes.extend_from_slice(&chars[..pos]);
725 if pos < 4 {
726 break;
727 }
728 }
729 core::str::from_utf8(&self.temp_bytes)
730 .map(|s| (s.to_owned(), count))
731 .map_err(|_| Error::BadString)
732 }
733
734 fn next_decoration(
735 &mut self,
736 inst: Instruction,
737 base_words: u16,
738 dec: &mut Decoration,
739 ) -> Result<(), Error> {
740 let raw = self.next()?;
741 let dec_typed = spirv::Decoration::from_u32(raw).ok_or(Error::InvalidDecoration(raw))?;
742 log::trace!("\t\t{}: {:?}", dec.debug_name(), dec_typed);
743 match dec_typed {
744 spirv::Decoration::BuiltIn => {
745 inst.expect(base_words + 2)?;
746 dec.built_in = Some(self.next()?);
747 }
748 spirv::Decoration::Location => {
749 inst.expect(base_words + 2)?;
750 dec.location = Some(self.next()?);
751 }
752 spirv::Decoration::DescriptorSet => {
753 inst.expect(base_words + 2)?;
754 dec.desc_set = Some(self.next()?);
755 }
756 spirv::Decoration::Binding => {
757 inst.expect(base_words + 2)?;
758 dec.desc_index = Some(self.next()?);
759 }
760 spirv::Decoration::BufferBlock => {
761 dec.storage_buffer = true;
762 }
763 spirv::Decoration::Offset => {
764 inst.expect(base_words + 2)?;
765 dec.offset = Some(self.next()?);
766 }
767 spirv::Decoration::ArrayStride => {
768 inst.expect(base_words + 2)?;
769 dec.array_stride = NonZeroU32::new(self.next()?);
770 }
771 spirv::Decoration::MatrixStride => {
772 inst.expect(base_words + 2)?;
773 dec.matrix_stride = NonZeroU32::new(self.next()?);
774 }
775 spirv::Decoration::Invariant => {
776 dec.invariant = true;
777 }
778 spirv::Decoration::NoPerspective => {
779 dec.interpolation = Some(crate::Interpolation::Linear);
780 }
781 spirv::Decoration::Flat => {
782 dec.interpolation = Some(crate::Interpolation::Flat);
783 }
784 spirv::Decoration::PerVertexKHR => {
785 dec.interpolation = Some(crate::Interpolation::PerVertex);
786 }
787 spirv::Decoration::Centroid => {
788 dec.sampling = Some(crate::Sampling::Centroid);
789 }
790 spirv::Decoration::Sample => {
791 dec.sampling = Some(crate::Sampling::Sample);
792 }
793 spirv::Decoration::NonReadable => {
794 dec.flags |= DecorationFlags::NON_READABLE;
795 }
796 spirv::Decoration::NonWritable => {
797 dec.flags |= DecorationFlags::NON_WRITABLE;
798 }
799 spirv::Decoration::ColMajor => {
800 dec.matrix_major = Some(Majority::Column);
801 }
802 spirv::Decoration::RowMajor => {
803 dec.matrix_major = Some(Majority::Row);
804 }
805 spirv::Decoration::SpecId => {
806 dec.specialization_constant_id = Some(self.next()?);
807 }
808 other => {
809 let level = match other {
810 spirv::Decoration::Block => log::Level::Debug,
814 _ => log::Level::Warn,
815 };
816
817 log::log!(level, "Unknown decoration {other:?}");
818 for _ in base_words + 1..inst.wc {
819 let _var = self.next()?;
820 }
821 }
822 }
823 Ok(())
824 }
825
826 fn get_expr_handle(
897 &self,
898 id: spirv::Word,
899 lookup: &LookupExpression,
900 ctx: &mut BlockContext,
901 emitter: &mut crate::proc::Emitter,
902 block: &mut crate::Block,
903 body_idx: BodyIndex,
904 ) -> Handle<crate::Expression> {
905 let expr_body_idx = ctx
907 .body_for_label
908 .get(&lookup.block_id)
909 .copied()
910 .unwrap_or(0);
911
912 if is_parent(body_idx, expr_body_idx, ctx) {
919 lookup.handle
920 } else {
921 let ty = self.lookup_type[&lookup.type_id].handle;
924 let local = ctx.local_arena.append(
925 crate::LocalVariable {
926 name: None,
927 ty,
928 init: None,
929 },
930 crate::Span::default(),
931 );
932
933 block.extend(emitter.finish(ctx.expressions));
934 let pointer = ctx.expressions.append(
935 crate::Expression::LocalVariable(local),
936 crate::Span::default(),
937 );
938 emitter.start(ctx.expressions);
939 let expr = ctx
940 .expressions
941 .append(crate::Expression::Load { pointer }, crate::Span::default());
942
943 ctx.phis.push(PhiExpression {
952 local,
953 expressions: vec![(id, lookup.block_id)],
954 });
955
956 expr
957 }
958 }
959
960 fn parse_expr_unary_op(
961 &mut self,
962 ctx: &mut BlockContext,
963 emitter: &mut crate::proc::Emitter,
964 block: &mut crate::Block,
965 block_id: spirv::Word,
966 body_idx: usize,
967 op: crate::UnaryOperator,
968 ) -> Result<(), Error> {
969 let start = self.data_offset;
970 let result_type_id = self.next()?;
971 let result_id = self.next()?;
972 let p_id = self.next()?;
973
974 let p_lexp = self.lookup_expression.lookup(p_id)?;
975 let handle = self.get_expr_handle(p_id, p_lexp, ctx, emitter, block, body_idx);
976
977 let expr = crate::Expression::Unary { op, expr: handle };
978 self.lookup_expression.insert(
979 result_id,
980 LookupExpression {
981 handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
982 type_id: result_type_id,
983 block_id,
984 },
985 );
986 Ok(())
987 }
988
989 fn parse_expr_binary_op(
990 &mut self,
991 ctx: &mut BlockContext,
992 emitter: &mut crate::proc::Emitter,
993 block: &mut crate::Block,
994 block_id: spirv::Word,
995 body_idx: usize,
996 op: crate::BinaryOperator,
997 ) -> Result<(), Error> {
998 let start = self.data_offset;
999 let result_type_id = self.next()?;
1000 let result_id = self.next()?;
1001 let p1_id = self.next()?;
1002 let p2_id = self.next()?;
1003
1004 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1005 let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1006 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1007 let right = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1008
1009 let expr = crate::Expression::Binary { op, left, right };
1010 self.lookup_expression.insert(
1011 result_id,
1012 LookupExpression {
1013 handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
1014 type_id: result_type_id,
1015 block_id,
1016 },
1017 );
1018 Ok(())
1019 }
1020
1021 fn parse_expr_unary_op_sign_adjusted(
1024 &mut self,
1025 ctx: &mut BlockContext,
1026 emitter: &mut crate::proc::Emitter,
1027 block: &mut crate::Block,
1028 block_id: spirv::Word,
1029 body_idx: usize,
1030 op: crate::UnaryOperator,
1031 ) -> Result<(), Error> {
1032 let start = self.data_offset;
1033 let result_type_id = self.next()?;
1034 let result_id = self.next()?;
1035 let p1_id = self.next()?;
1036 let span = self.span_from_with_op(start);
1037
1038 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1039 let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1040
1041 let result_lookup_ty = self.lookup_type.lookup(result_type_id)?;
1042 let kind = ctx.module.types[result_lookup_ty.handle]
1043 .inner
1044 .scalar_kind()
1045 .unwrap();
1046
1047 let expr = crate::Expression::Unary {
1048 op,
1049 expr: if p1_lexp.type_id == result_type_id {
1050 left
1051 } else {
1052 ctx.expressions.append(
1053 crate::Expression::As {
1054 expr: left,
1055 kind,
1056 convert: None,
1057 },
1058 span,
1059 )
1060 },
1061 };
1062
1063 self.lookup_expression.insert(
1064 result_id,
1065 LookupExpression {
1066 handle: ctx.expressions.append(expr, span),
1067 type_id: result_type_id,
1068 block_id,
1069 },
1070 );
1071 Ok(())
1072 }
1073
1074 #[allow(clippy::too_many_arguments)]
1078 fn parse_expr_binary_op_sign_adjusted(
1079 &mut self,
1080 ctx: &mut BlockContext,
1081 emitter: &mut crate::proc::Emitter,
1082 block: &mut crate::Block,
1083 block_id: spirv::Word,
1084 body_idx: usize,
1085 op: crate::BinaryOperator,
1086 anchor: SignAnchor,
1090 ) -> Result<(), Error> {
1091 let start = self.data_offset;
1092 let result_type_id = self.next()?;
1093 let result_id = self.next()?;
1094 let p1_id = self.next()?;
1095 let p2_id = self.next()?;
1096 let span = self.span_from_with_op(start);
1097
1098 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1099 let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1100 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1101 let right = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1102
1103 let expected_type_id = match anchor {
1104 SignAnchor::Result => result_type_id,
1105 SignAnchor::Operand => p1_lexp.type_id,
1106 };
1107 let expected_lookup_ty = self.lookup_type.lookup(expected_type_id)?;
1108 let kind = ctx.module.types[expected_lookup_ty.handle]
1109 .inner
1110 .scalar_kind()
1111 .unwrap();
1112
1113 let expr = crate::Expression::Binary {
1114 op,
1115 left: if p1_lexp.type_id == expected_type_id {
1116 left
1117 } else {
1118 ctx.expressions.append(
1119 crate::Expression::As {
1120 expr: left,
1121 kind,
1122 convert: None,
1123 },
1124 span,
1125 )
1126 },
1127 right: if p2_lexp.type_id == expected_type_id {
1128 right
1129 } else {
1130 ctx.expressions.append(
1131 crate::Expression::As {
1132 expr: right,
1133 kind,
1134 convert: None,
1135 },
1136 span,
1137 )
1138 },
1139 };
1140
1141 self.lookup_expression.insert(
1142 result_id,
1143 LookupExpression {
1144 handle: ctx.expressions.append(expr, span),
1145 type_id: result_type_id,
1146 block_id,
1147 },
1148 );
1149 Ok(())
1150 }
1151
1152 #[allow(clippy::too_many_arguments)]
1156 fn parse_expr_int_comparison(
1157 &mut self,
1158 ctx: &mut BlockContext,
1159 emitter: &mut crate::proc::Emitter,
1160 block: &mut crate::Block,
1161 block_id: spirv::Word,
1162 body_idx: usize,
1163 op: crate::BinaryOperator,
1164 kind: crate::ScalarKind,
1165 ) -> Result<(), Error> {
1166 let start = self.data_offset;
1167 let result_type_id = self.next()?;
1168 let result_id = self.next()?;
1169 let p1_id = self.next()?;
1170 let p2_id = self.next()?;
1171 let span = self.span_from_with_op(start);
1172
1173 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1174 let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1175 let p1_lookup_ty = self.lookup_type.lookup(p1_lexp.type_id)?;
1176 let p1_kind = ctx.module.types[p1_lookup_ty.handle]
1177 .inner
1178 .scalar_kind()
1179 .unwrap();
1180 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1181 let right = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1182 let p2_lookup_ty = self.lookup_type.lookup(p2_lexp.type_id)?;
1183 let p2_kind = ctx.module.types[p2_lookup_ty.handle]
1184 .inner
1185 .scalar_kind()
1186 .unwrap();
1187
1188 let expr = crate::Expression::Binary {
1189 op,
1190 left: if p1_kind == kind {
1191 left
1192 } else {
1193 ctx.expressions.append(
1194 crate::Expression::As {
1195 expr: left,
1196 kind,
1197 convert: None,
1198 },
1199 span,
1200 )
1201 },
1202 right: if p2_kind == kind {
1203 right
1204 } else {
1205 ctx.expressions.append(
1206 crate::Expression::As {
1207 expr: right,
1208 kind,
1209 convert: None,
1210 },
1211 span,
1212 )
1213 },
1214 };
1215
1216 self.lookup_expression.insert(
1217 result_id,
1218 LookupExpression {
1219 handle: ctx.expressions.append(expr, span),
1220 type_id: result_type_id,
1221 block_id,
1222 },
1223 );
1224 Ok(())
1225 }
1226
1227 fn parse_expr_shift_op(
1228 &mut self,
1229 ctx: &mut BlockContext,
1230 emitter: &mut crate::proc::Emitter,
1231 block: &mut crate::Block,
1232 block_id: spirv::Word,
1233 body_idx: usize,
1234 op: crate::BinaryOperator,
1235 ) -> Result<(), Error> {
1236 let start = self.data_offset;
1237 let result_type_id = self.next()?;
1238 let result_id = self.next()?;
1239 let p1_id = self.next()?;
1240 let p2_id = self.next()?;
1241
1242 let span = self.span_from_with_op(start);
1243
1244 let p1_lexp = self.lookup_expression.lookup(p1_id)?;
1245 let left = self.get_expr_handle(p1_id, p1_lexp, ctx, emitter, block, body_idx);
1246 let p2_lexp = self.lookup_expression.lookup(p2_id)?;
1247 let p2_handle = self.get_expr_handle(p2_id, p2_lexp, ctx, emitter, block, body_idx);
1248 let right = ctx.expressions.append(
1250 crate::Expression::As {
1251 expr: p2_handle,
1252 kind: crate::ScalarKind::Uint,
1253 convert: None,
1254 },
1255 span,
1256 );
1257
1258 let expr = crate::Expression::Binary { op, left, right };
1259 self.lookup_expression.insert(
1260 result_id,
1261 LookupExpression {
1262 handle: ctx.expressions.append(expr, span),
1263 type_id: result_type_id,
1264 block_id,
1265 },
1266 );
1267 Ok(())
1268 }
1269
1270 fn parse_expr_derivative(
1271 &mut self,
1272 ctx: &mut BlockContext,
1273 emitter: &mut crate::proc::Emitter,
1274 block: &mut crate::Block,
1275 block_id: spirv::Word,
1276 body_idx: usize,
1277 (axis, ctrl): (crate::DerivativeAxis, crate::DerivativeControl),
1278 ) -> Result<(), Error> {
1279 let start = self.data_offset;
1280 let result_type_id = self.next()?;
1281 let result_id = self.next()?;
1282 let arg_id = self.next()?;
1283
1284 let arg_lexp = self.lookup_expression.lookup(arg_id)?;
1285 let arg_handle = self.get_expr_handle(arg_id, arg_lexp, ctx, emitter, block, body_idx);
1286
1287 let expr = crate::Expression::Derivative {
1288 axis,
1289 ctrl,
1290 expr: arg_handle,
1291 };
1292 self.lookup_expression.insert(
1293 result_id,
1294 LookupExpression {
1295 handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
1296 type_id: result_type_id,
1297 block_id,
1298 },
1299 );
1300 Ok(())
1301 }
1302
1303 #[allow(clippy::too_many_arguments)]
1304 fn insert_composite(
1305 &self,
1306 root_expr: Handle<crate::Expression>,
1307 root_type_id: spirv::Word,
1308 object_expr: Handle<crate::Expression>,
1309 selections: &[spirv::Word],
1310 type_arena: &UniqueArena<crate::Type>,
1311 expressions: &mut Arena<crate::Expression>,
1312 span: crate::Span,
1313 ) -> Result<Handle<crate::Expression>, Error> {
1314 let selection = match selections.first() {
1315 Some(&index) => index,
1316 None => return Ok(object_expr),
1317 };
1318 let root_span = expressions.get_span(root_expr);
1319 let root_lookup = self.lookup_type.lookup(root_type_id)?;
1320
1321 let (count, child_type_id) = match type_arena[root_lookup.handle].inner {
1322 crate::TypeInner::Struct { ref members, .. } => {
1323 let child_member = self
1324 .lookup_member
1325 .get(&(root_lookup.handle, selection))
1326 .ok_or(Error::InvalidAccessType(root_type_id))?;
1327 (members.len(), child_member.type_id)
1328 }
1329 crate::TypeInner::Array { size, .. } => {
1330 let size = match size {
1331 crate::ArraySize::Constant(size) => size.get(),
1332 crate::ArraySize::Pending(_) => {
1333 unreachable!();
1334 }
1335 crate::ArraySize::Dynamic => {
1337 return Err(Error::InvalidAccessType(root_type_id))
1338 }
1339 };
1340
1341 let child_type_id = root_lookup
1342 .base_id
1343 .ok_or(Error::InvalidAccessType(root_type_id))?;
1344
1345 (size as usize, child_type_id)
1346 }
1347 crate::TypeInner::Vector { size, .. }
1348 | crate::TypeInner::Matrix { columns: size, .. } => {
1349 let child_type_id = root_lookup
1350 .base_id
1351 .ok_or(Error::InvalidAccessType(root_type_id))?;
1352 (size as usize, child_type_id)
1353 }
1354 _ => return Err(Error::InvalidAccessType(root_type_id)),
1355 };
1356
1357 let mut components = Vec::with_capacity(count);
1358 for index in 0..count as u32 {
1359 let expr = expressions.append(
1360 crate::Expression::AccessIndex {
1361 base: root_expr,
1362 index,
1363 },
1364 if index == selection { span } else { root_span },
1365 );
1366 components.push(expr);
1367 }
1368 components[selection as usize] = self.insert_composite(
1369 components[selection as usize],
1370 child_type_id,
1371 object_expr,
1372 &selections[1..],
1373 type_arena,
1374 expressions,
1375 span,
1376 )?;
1377
1378 Ok(expressions.append(
1379 crate::Expression::Compose {
1380 ty: root_lookup.handle,
1381 components,
1382 },
1383 span,
1384 ))
1385 }
1386
1387 fn get_exp_and_base_ty_handles(
1401 &self,
1402 pointer_id: spirv::Word,
1403 ctx: &mut BlockContext,
1404 emitter: &mut crate::proc::Emitter,
1405 block: &mut crate::Block,
1406 body_idx: usize,
1407 ) -> Result<(Handle<crate::Expression>, Handle<crate::Type>), Error> {
1408 log::trace!("\t\t\tlooking up pointer expr {pointer_id:?}");
1409 let p_lexp_handle;
1410 let p_lexp_ty_id;
1411 {
1412 let lexp = self.lookup_expression.lookup(pointer_id)?;
1413 p_lexp_handle = self.get_expr_handle(pointer_id, lexp, ctx, emitter, block, body_idx);
1414 p_lexp_ty_id = lexp.type_id;
1415 };
1416
1417 log::trace!("\t\t\tlooking up pointer type {pointer_id:?}");
1418 let p_ty = self.lookup_type.lookup(p_lexp_ty_id)?;
1419 let p_ty_base_id = p_ty.base_id.ok_or(Error::InvalidAccessType(p_lexp_ty_id))?;
1420
1421 log::trace!("\t\t\tlooking up pointer base type {p_ty_base_id:?} of {p_ty:?}");
1422 let p_base_ty = self.lookup_type.lookup(p_ty_base_id)?;
1423
1424 Ok((p_lexp_handle, p_base_ty.handle))
1425 }
1426
1427 #[allow(clippy::too_many_arguments)]
1428 fn parse_atomic_expr_with_value(
1429 &mut self,
1430 inst: Instruction,
1431 emitter: &mut crate::proc::Emitter,
1432 ctx: &mut BlockContext,
1433 block: &mut crate::Block,
1434 block_id: spirv::Word,
1435 body_idx: usize,
1436 atomic_function: crate::AtomicFunction,
1437 ) -> Result<(), Error> {
1438 inst.expect(7)?;
1439 let start = self.data_offset;
1440 let result_type_id = self.next()?;
1441 let result_id = self.next()?;
1442 let pointer_id = self.next()?;
1443 let _scope_id = self.next()?;
1444 let _memory_semantics_id = self.next()?;
1445 let value_id = self.next()?;
1446 let span = self.span_from_with_op(start);
1447
1448 let (p_lexp_handle, p_base_ty_handle) =
1449 self.get_exp_and_base_ty_handles(pointer_id, ctx, emitter, block, body_idx)?;
1450
1451 log::trace!("\t\t\tlooking up value expr {value_id:?}");
1452 let v_lexp_handle = self.lookup_expression.lookup(value_id)?.handle;
1453
1454 block.extend(emitter.finish(ctx.expressions));
1455 let r_lexp_handle = {
1457 let expr = crate::Expression::AtomicResult {
1458 ty: p_base_ty_handle,
1459 comparison: false,
1460 };
1461 let handle = ctx.expressions.append(expr, span);
1462 self.lookup_expression.insert(
1463 result_id,
1464 LookupExpression {
1465 handle,
1466 type_id: result_type_id,
1467 block_id,
1468 },
1469 );
1470 handle
1471 };
1472 emitter.start(ctx.expressions);
1473
1474 let stmt = crate::Statement::Atomic {
1476 pointer: p_lexp_handle,
1477 fun: atomic_function,
1478 value: v_lexp_handle,
1479 result: Some(r_lexp_handle),
1480 };
1481 block.push(stmt, span);
1482
1483 self.record_atomic_access(ctx, p_lexp_handle)?;
1485
1486 Ok(())
1487 }
1488
1489 fn make_expression_storage(
1490 &mut self,
1491 globals: &Arena<crate::GlobalVariable>,
1492 constants: &Arena<crate::Constant>,
1493 overrides: &Arena<crate::Override>,
1494 ) -> Arena<crate::Expression> {
1495 let mut expressions = Arena::new();
1496 #[allow(clippy::panic)]
1497 {
1498 assert!(self.lookup_expression.is_empty());
1499 }
1500 for (&id, var) in self.lookup_variable.iter() {
1502 let span = globals.get_span(var.handle);
1503 let handle = expressions.append(crate::Expression::GlobalVariable(var.handle), span);
1504 self.lookup_expression.insert(
1505 id,
1506 LookupExpression {
1507 type_id: var.type_id,
1508 handle,
1509 block_id: 0,
1513 },
1514 );
1515 }
1516 for (&id, con) in self.lookup_constant.iter() {
1518 let (expr, span) = match con.inner {
1519 Constant::Constant(c) => (crate::Expression::Constant(c), constants.get_span(c)),
1520 Constant::Override(o) => (crate::Expression::Override(o), overrides.get_span(o)),
1521 };
1522 let handle = expressions.append(expr, span);
1523 self.lookup_expression.insert(
1524 id,
1525 LookupExpression {
1526 type_id: con.type_id,
1527 handle,
1528 block_id: 0,
1532 },
1533 );
1534 }
1535 expressions
1537 }
1538
1539 fn switch(&mut self, state: ModuleState, op: spirv::Op) -> Result<(), Error> {
1540 if state < self.state {
1541 Err(Error::UnsupportedInstruction(self.state, op))
1542 } else {
1543 self.state = state;
1544 Ok(())
1545 }
1546 }
1547
1548 fn patch_statements(
1551 &mut self,
1552 statements: &mut crate::Block,
1553 expressions: &mut Arena<crate::Expression>,
1554 fun_parameter_sampling: &mut [image::SamplingFlags],
1555 ) -> Result<(), Error> {
1556 use crate::Statement as S;
1557 let mut i = 0usize;
1558 while i < statements.len() {
1559 match statements[i] {
1560 S::Emit(_) => {}
1561 S::Block(ref mut block) => {
1562 self.patch_statements(block, expressions, fun_parameter_sampling)?;
1563 }
1564 S::If {
1565 condition: _,
1566 ref mut accept,
1567 ref mut reject,
1568 } => {
1569 self.patch_statements(reject, expressions, fun_parameter_sampling)?;
1570 self.patch_statements(accept, expressions, fun_parameter_sampling)?;
1571 }
1572 S::Switch {
1573 selector: _,
1574 ref mut cases,
1575 } => {
1576 for case in cases.iter_mut() {
1577 self.patch_statements(&mut case.body, expressions, fun_parameter_sampling)?;
1578 }
1579 }
1580 S::Loop {
1581 ref mut body,
1582 ref mut continuing,
1583 break_if: _,
1584 } => {
1585 self.patch_statements(body, expressions, fun_parameter_sampling)?;
1586 self.patch_statements(continuing, expressions, fun_parameter_sampling)?;
1587 }
1588 S::Break
1589 | S::Continue
1590 | S::Return { .. }
1591 | S::Kill
1592 | S::ControlBarrier(_)
1593 | S::MemoryBarrier(_)
1594 | S::Store { .. }
1595 | S::ImageStore { .. }
1596 | S::Atomic { .. }
1597 | S::ImageAtomic { .. }
1598 | S::RayQuery { .. }
1599 | S::SubgroupBallot { .. }
1600 | S::SubgroupCollectiveOperation { .. }
1601 | S::SubgroupGather { .. } => {}
1602 S::Call {
1603 function: ref mut callee,
1604 ref arguments,
1605 ..
1606 } => {
1607 let fun_id = self.deferred_function_calls[callee.index()];
1608 let fun_lookup = self.lookup_function.lookup(fun_id)?;
1609 *callee = fun_lookup.handle;
1610
1611 for (arg_index, arg) in arguments.iter().enumerate() {
1613 let flags = match fun_lookup.parameters_sampling.get(arg_index) {
1614 Some(&flags) if !flags.is_empty() => flags,
1615 _ => continue,
1616 };
1617
1618 match expressions[*arg] {
1619 crate::Expression::GlobalVariable(handle) => {
1620 if let Some(sampling) = self.handle_sampling.get_mut(&handle) {
1621 *sampling |= flags
1622 }
1623 }
1624 crate::Expression::FunctionArgument(i) => {
1625 fun_parameter_sampling[i as usize] |= flags;
1626 }
1627 ref other => return Err(Error::InvalidGlobalVar(other.clone())),
1628 }
1629 }
1630 }
1631 S::WorkGroupUniformLoad { .. } => unreachable!(),
1632 S::CooperativeStore { .. } => unreachable!(),
1633 }
1634 i += 1;
1635 }
1636 Ok(())
1637 }
1638
1639 fn patch_function(
1640 &mut self,
1641 handle: Option<Handle<crate::Function>>,
1642 fun: &mut crate::Function,
1643 ) -> Result<(), Error> {
1644 let (fun_id, mut parameters_sampling) = match handle {
1646 Some(h) => {
1647 let (&fun_id, lookup) = self
1648 .lookup_function
1649 .iter_mut()
1650 .find(|&(_, ref lookup)| lookup.handle == h)
1651 .unwrap();
1652 (fun_id, mem::take(&mut lookup.parameters_sampling))
1653 }
1654 None => (0, Vec::new()),
1655 };
1656
1657 for (_, expr) in fun.expressions.iter_mut() {
1658 if let crate::Expression::CallResult(ref mut function) = *expr {
1659 let fun_id = self.deferred_function_calls[function.index()];
1660 *function = self.lookup_function.lookup(fun_id)?.handle;
1661 }
1662 }
1663
1664 self.patch_statements(
1665 &mut fun.body,
1666 &mut fun.expressions,
1667 &mut parameters_sampling,
1668 )?;
1669
1670 if let Some(lookup) = self.lookup_function.get_mut(&fun_id) {
1671 lookup.parameters_sampling = parameters_sampling;
1672 }
1673 Ok(())
1674 }
1675
1676 pub fn parse(mut self) -> Result<crate::Module, Error> {
1677 let mut module = {
1678 if self.next()? != spirv::MAGIC_NUMBER {
1679 return Err(Error::InvalidHeader);
1680 }
1681 let version_raw = self.next()?;
1682 let generator = self.next()?;
1683 let _bound = self.next()?;
1684 let _schema = self.next()?;
1685 log::debug!("Generated by {generator} version {version_raw:x}");
1686 crate::Module::default()
1687 };
1688
1689 self.layouter.clear();
1690 self.dummy_functions = Arena::new();
1691 self.lookup_function.clear();
1692 self.function_call_graph.clear();
1693
1694 loop {
1695 use spirv::Op;
1696
1697 let inst = match self.next_inst() {
1698 Ok(inst) => inst,
1699 Err(Error::IncompleteData) => break,
1700 Err(other) => return Err(other),
1701 };
1702 log::debug!("\t{:?} [{}]", inst.op, inst.wc);
1703
1704 match inst.op {
1705 Op::Capability => self.parse_capability(inst),
1706 Op::Extension => self.parse_extension(inst),
1707 Op::ExtInstImport => self.parse_ext_inst_import(inst),
1708 Op::MemoryModel => self.parse_memory_model(inst),
1709 Op::EntryPoint => self.parse_entry_point(inst),
1710 Op::ExecutionMode => self.parse_execution_mode(inst),
1711 Op::String => self.parse_string(inst),
1712 Op::Source => self.parse_source(inst),
1713 Op::SourceExtension => self.parse_source_extension(inst),
1714 Op::Name => self.parse_name(inst),
1715 Op::MemberName => self.parse_member_name(inst),
1716 Op::ModuleProcessed => self.parse_module_processed(inst),
1717 Op::Decorate => self.parse_decorate(inst),
1718 Op::MemberDecorate => self.parse_member_decorate(inst),
1719 Op::TypeVoid => self.parse_type_void(inst),
1720 Op::TypeBool => self.parse_type_bool(inst, &mut module),
1721 Op::TypeInt => self.parse_type_int(inst, &mut module),
1722 Op::TypeFloat => self.parse_type_float(inst, &mut module),
1723 Op::TypeVector => self.parse_type_vector(inst, &mut module),
1724 Op::TypeMatrix => self.parse_type_matrix(inst, &mut module),
1725 Op::TypeFunction => self.parse_type_function(inst),
1726 Op::TypePointer => self.parse_type_pointer(inst, &mut module),
1727 Op::TypeArray => self.parse_type_array(inst, &mut module),
1728 Op::TypeRuntimeArray => self.parse_type_runtime_array(inst, &mut module),
1729 Op::TypeStruct => self.parse_type_struct(inst, &mut module),
1730 Op::TypeImage => self.parse_type_image(inst, &mut module),
1731 Op::TypeSampledImage => self.parse_type_sampled_image(inst),
1732 Op::TypeSampler => self.parse_type_sampler(inst, &mut module),
1733 Op::Constant | Op::SpecConstant => self.parse_constant(inst, &mut module),
1734 Op::ConstantComposite | Op::SpecConstantComposite => {
1735 self.parse_composite_constant(inst, &mut module)
1736 }
1737 Op::ConstantNull | Op::Undef => self.parse_null_constant(inst, &mut module),
1738 Op::ConstantTrue | Op::SpecConstantTrue => {
1739 self.parse_bool_constant(inst, true, &mut module)
1740 }
1741 Op::ConstantFalse | Op::SpecConstantFalse => {
1742 self.parse_bool_constant(inst, false, &mut module)
1743 }
1744 Op::Variable => self.parse_global_variable(inst, &mut module),
1745 Op::Function => {
1746 self.switch(ModuleState::Function, inst.op)?;
1747 inst.expect(5)?;
1748 self.parse_function(&mut module)
1749 }
1750 Op::ExtInst => {
1751 let _ = self.next()?;
1753 let _ = self.next()?;
1754 let set_id = self.next()?;
1755 if Some(set_id) == self.ext_non_semantic_id {
1756 for _ in 0..inst.wc - 4 {
1758 self.next()?;
1759 }
1760 Ok(())
1761 } else {
1762 return Err(Error::UnsupportedInstruction(self.state, inst.op));
1763 }
1764 }
1765 _ => Err(Error::UnsupportedInstruction(self.state, inst.op)), }?;
1767 }
1768
1769 if !self.upgrade_atomics.is_empty() {
1770 log::debug!("Upgrading atomic pointers...");
1771 module.upgrade_atomics(&self.upgrade_atomics)?;
1772 }
1773
1774 for (ep, fun_id) in mem::take(&mut self.deferred_entry_points) {
1777 self.process_entry_point(&mut module, ep, fun_id)?;
1778 }
1779
1780 log::debug!("Patching...");
1781 {
1782 let mut nodes = petgraph::algo::toposort(&self.function_call_graph, None)
1783 .map_err(|cycle| Error::FunctionCallCycle(cycle.node_id()))?;
1784 nodes.reverse(); let mut functions = mem::take(&mut module.functions);
1786 for fun_id in nodes {
1787 if fun_id > !(functions.len() as u32) {
1788 continue;
1790 }
1791 let lookup = self.lookup_function.get_mut(&fun_id).unwrap();
1792 let fun = mem::take(&mut functions[lookup.handle]);
1794 lookup.handle = module
1796 .functions
1797 .append(fun, functions.get_span(lookup.handle));
1798 }
1799 }
1800 for (handle, fun) in module.functions.iter_mut() {
1802 self.patch_function(Some(handle), fun)?;
1803 }
1804 for ep in module.entry_points.iter_mut() {
1805 self.patch_function(None, &mut ep.function)?;
1806 }
1807
1808 for (handle, flags) in self.handle_sampling.drain() {
1810 if !image::patch_comparison_type(
1811 flags,
1812 module.global_variables.get_mut(handle),
1813 &mut module.types,
1814 ) {
1815 return Err(Error::InconsistentComparisonSampling(handle));
1816 }
1817 }
1818
1819 if !self.future_decor.is_empty() {
1820 log::debug!("Unused item decorations: {:?}", self.future_decor);
1821 self.future_decor.clear();
1822 }
1823 if !self.future_member_decor.is_empty() {
1824 log::debug!("Unused member decorations: {:?}", self.future_member_decor);
1825 self.future_member_decor.clear();
1826 }
1827
1828 Ok(module)
1829 }
1830
1831 fn parse_capability(&mut self, inst: Instruction) -> Result<(), Error> {
1832 self.switch(ModuleState::Capability, inst.op)?;
1833 inst.expect(2)?;
1834 let capability = self.next()?;
1835 let cap =
1836 spirv::Capability::from_u32(capability).ok_or(Error::UnknownCapability(capability))?;
1837 if !SUPPORTED_CAPABILITIES.contains(&cap) {
1838 if self.options.strict_capabilities {
1839 return Err(Error::UnsupportedCapability(cap));
1840 } else {
1841 log::warn!("Unknown capability {cap:?}");
1842 }
1843 }
1844 Ok(())
1845 }
1846
1847 fn parse_extension(&mut self, inst: Instruction) -> Result<(), Error> {
1848 self.switch(ModuleState::Extension, inst.op)?;
1849 inst.expect_at_least(2)?;
1850 let (name, left) = self.next_string(inst.wc - 1)?;
1851 if left != 0 {
1852 return Err(Error::InvalidOperand);
1853 }
1854 if !SUPPORTED_EXTENSIONS.contains(&name.as_str()) {
1855 return Err(Error::UnsupportedExtension(name));
1856 }
1857 Ok(())
1858 }
1859
1860 fn parse_ext_inst_import(&mut self, inst: Instruction) -> Result<(), Error> {
1861 self.switch(ModuleState::Extension, inst.op)?;
1862 inst.expect_at_least(3)?;
1863 let result_id = self.next()?;
1864 let (name, left) = self.next_string(inst.wc - 2)?;
1865 if left != 0 {
1866 return Err(Error::InvalidOperand);
1867 }
1868 if &name == "GLSL.std.450" {
1869 self.ext_glsl_id = Some(result_id);
1870 } else if &name == "NonSemantic.Shader.DebugInfo.100" {
1871 self.ext_non_semantic_id = Some(result_id);
1876 } else {
1877 return Err(Error::UnsupportedExtSet(name));
1878 }
1879 Ok(())
1880 }
1881
1882 fn parse_memory_model(&mut self, inst: Instruction) -> Result<(), Error> {
1883 self.switch(ModuleState::MemoryModel, inst.op)?;
1884 inst.expect(3)?;
1885 let _addressing_model = self.next()?;
1886 let _memory_model = self.next()?;
1887 Ok(())
1888 }
1889
1890 fn parse_entry_point(&mut self, inst: Instruction) -> Result<(), Error> {
1891 self.switch(ModuleState::EntryPoint, inst.op)?;
1892 inst.expect_at_least(4)?;
1893 let exec_model = self.next()?;
1894 let exec_model = spirv::ExecutionModel::from_u32(exec_model)
1895 .ok_or(Error::UnsupportedExecutionModel(exec_model))?;
1896 let function_id = self.next()?;
1897 let (name, left) = self.next_string(inst.wc - 3)?;
1898 let ep = EntryPoint {
1899 stage: match exec_model {
1900 spirv::ExecutionModel::Vertex => crate::ShaderStage::Vertex,
1901 spirv::ExecutionModel::Fragment => crate::ShaderStage::Fragment,
1902 spirv::ExecutionModel::GLCompute => crate::ShaderStage::Compute,
1903 spirv::ExecutionModel::TaskEXT => crate::ShaderStage::Task,
1904 spirv::ExecutionModel::MeshEXT => crate::ShaderStage::Mesh,
1905 _ => return Err(Error::UnsupportedExecutionModel(exec_model as u32)),
1906 },
1907 name,
1908 early_depth_test: None,
1909 workgroup_size: [0; 3],
1910 variable_ids: self.data.by_ref().take(left as usize).collect(),
1911 };
1912 self.lookup_entry_point.insert(function_id, ep);
1913 Ok(())
1914 }
1915
1916 fn parse_execution_mode(&mut self, inst: Instruction) -> Result<(), Error> {
1917 use spirv::ExecutionMode;
1918
1919 self.switch(ModuleState::ExecutionMode, inst.op)?;
1920 inst.expect_at_least(3)?;
1921
1922 let ep_id = self.next()?;
1923 let mode_id = self.next()?;
1924 let args: Vec<spirv::Word> = self.data.by_ref().take(inst.wc as usize - 3).collect();
1925
1926 let ep = self
1927 .lookup_entry_point
1928 .get_mut(&ep_id)
1929 .ok_or(Error::InvalidId(ep_id))?;
1930 let mode =
1931 ExecutionMode::from_u32(mode_id).ok_or(Error::UnsupportedExecutionMode(mode_id))?;
1932
1933 match mode {
1934 ExecutionMode::EarlyFragmentTests => {
1935 ep.early_depth_test = Some(crate::EarlyDepthTest::Force);
1936 }
1937 ExecutionMode::DepthUnchanged => {
1938 if let &mut Some(ref mut early_depth_test) = &mut ep.early_depth_test {
1939 if let &mut crate::EarlyDepthTest::Allow {
1940 ref mut conservative,
1941 } = early_depth_test
1942 {
1943 *conservative = crate::ConservativeDepth::Unchanged;
1944 }
1945 } else {
1946 ep.early_depth_test = Some(crate::EarlyDepthTest::Allow {
1947 conservative: crate::ConservativeDepth::Unchanged,
1948 });
1949 }
1950 }
1951 ExecutionMode::DepthGreater => {
1952 if let &mut Some(ref mut early_depth_test) = &mut ep.early_depth_test {
1953 if let &mut crate::EarlyDepthTest::Allow {
1954 ref mut conservative,
1955 } = early_depth_test
1956 {
1957 *conservative = crate::ConservativeDepth::GreaterEqual;
1958 }
1959 } else {
1960 ep.early_depth_test = Some(crate::EarlyDepthTest::Allow {
1961 conservative: crate::ConservativeDepth::GreaterEqual,
1962 });
1963 }
1964 }
1965 ExecutionMode::DepthLess => {
1966 if let &mut Some(ref mut early_depth_test) = &mut ep.early_depth_test {
1967 if let &mut crate::EarlyDepthTest::Allow {
1968 ref mut conservative,
1969 } = early_depth_test
1970 {
1971 *conservative = crate::ConservativeDepth::LessEqual;
1972 }
1973 } else {
1974 ep.early_depth_test = Some(crate::EarlyDepthTest::Allow {
1975 conservative: crate::ConservativeDepth::LessEqual,
1976 });
1977 }
1978 }
1979 ExecutionMode::DepthReplacing => {
1980 }
1982 ExecutionMode::OriginUpperLeft => {
1983 }
1985 ExecutionMode::LocalSize => {
1986 ep.workgroup_size = [args[0], args[1], args[2]];
1987 }
1988 _ => {
1989 return Err(Error::UnsupportedExecutionMode(mode_id));
1990 }
1991 }
1992
1993 Ok(())
1994 }
1995
1996 fn parse_string(&mut self, inst: Instruction) -> Result<(), Error> {
1997 self.switch(ModuleState::Source, inst.op)?;
1998 inst.expect_at_least(3)?;
1999 let _id = self.next()?;
2000 let (_name, _) = self.next_string(inst.wc - 2)?;
2001 Ok(())
2002 }
2003
2004 fn parse_source(&mut self, inst: Instruction) -> Result<(), Error> {
2005 self.switch(ModuleState::Source, inst.op)?;
2006 for _ in 1..inst.wc {
2007 let _ = self.next()?;
2008 }
2009 Ok(())
2010 }
2011
2012 fn parse_source_extension(&mut self, inst: Instruction) -> Result<(), Error> {
2013 self.switch(ModuleState::Source, inst.op)?;
2014 inst.expect_at_least(2)?;
2015 let (_name, _) = self.next_string(inst.wc - 1)?;
2016 Ok(())
2017 }
2018
2019 fn parse_name(&mut self, inst: Instruction) -> Result<(), Error> {
2020 self.switch(ModuleState::Name, inst.op)?;
2021 inst.expect_at_least(3)?;
2022 let id = self.next()?;
2023 let (name, left) = self.next_string(inst.wc - 2)?;
2024 if left != 0 {
2025 return Err(Error::InvalidOperand);
2026 }
2027 self.future_decor.entry(id).or_default().name = Some(name);
2028 Ok(())
2029 }
2030
2031 fn parse_member_name(&mut self, inst: Instruction) -> Result<(), Error> {
2032 self.switch(ModuleState::Name, inst.op)?;
2033 inst.expect_at_least(4)?;
2034 let id = self.next()?;
2035 let member = self.next()?;
2036 let (name, left) = self.next_string(inst.wc - 3)?;
2037 if left != 0 {
2038 return Err(Error::InvalidOperand);
2039 }
2040
2041 self.future_member_decor
2042 .entry((id, member))
2043 .or_default()
2044 .name = Some(name);
2045 Ok(())
2046 }
2047
2048 fn parse_module_processed(&mut self, inst: Instruction) -> Result<(), Error> {
2049 self.switch(ModuleState::Name, inst.op)?;
2050 inst.expect_at_least(2)?;
2051 let (_info, left) = self.next_string(inst.wc - 1)?;
2052 if left != 0 {
2054 return Err(Error::InvalidOperand);
2055 }
2056 Ok(())
2057 }
2058
2059 fn parse_decorate(&mut self, inst: Instruction) -> Result<(), Error> {
2060 self.switch(ModuleState::Annotation, inst.op)?;
2061 inst.expect_at_least(3)?;
2062 let id = self.next()?;
2063 let mut dec = self.future_decor.remove(&id).unwrap_or_default();
2064 self.next_decoration(inst, 2, &mut dec)?;
2065 self.future_decor.insert(id, dec);
2066 Ok(())
2067 }
2068
2069 fn parse_member_decorate(&mut self, inst: Instruction) -> Result<(), Error> {
2070 self.switch(ModuleState::Annotation, inst.op)?;
2071 inst.expect_at_least(4)?;
2072 let id = self.next()?;
2073 let member = self.next()?;
2074
2075 let mut dec = self
2076 .future_member_decor
2077 .remove(&(id, member))
2078 .unwrap_or_default();
2079 self.next_decoration(inst, 3, &mut dec)?;
2080 self.future_member_decor.insert((id, member), dec);
2081 Ok(())
2082 }
2083
2084 fn parse_type_void(&mut self, inst: Instruction) -> Result<(), Error> {
2085 self.switch(ModuleState::Type, inst.op)?;
2086 inst.expect(2)?;
2087 let id = self.next()?;
2088 self.lookup_void_type = Some(id);
2089 Ok(())
2090 }
2091
2092 fn parse_type_bool(
2093 &mut self,
2094 inst: Instruction,
2095 module: &mut crate::Module,
2096 ) -> Result<(), Error> {
2097 let start = self.data_offset;
2098 self.switch(ModuleState::Type, inst.op)?;
2099 inst.expect(2)?;
2100 let id = self.next()?;
2101 let inner = crate::TypeInner::Scalar(crate::Scalar::BOOL);
2102 self.lookup_type.insert(
2103 id,
2104 LookupType {
2105 handle: module.types.insert(
2106 crate::Type {
2107 name: self.future_decor.remove(&id).and_then(|dec| dec.name),
2108 inner,
2109 },
2110 self.span_from_with_op(start),
2111 ),
2112 base_id: None,
2113 },
2114 );
2115 Ok(())
2116 }
2117
2118 fn parse_type_int(
2119 &mut self,
2120 inst: Instruction,
2121 module: &mut crate::Module,
2122 ) -> Result<(), Error> {
2123 let start = self.data_offset;
2124 self.switch(ModuleState::Type, inst.op)?;
2125 inst.expect(4)?;
2126 let id = self.next()?;
2127 let width = self.next()?;
2128 let sign = self.next()?;
2129 let inner = crate::TypeInner::Scalar(crate::Scalar {
2130 kind: match sign {
2131 0 => crate::ScalarKind::Uint,
2132 1 => crate::ScalarKind::Sint,
2133 _ => return Err(Error::InvalidSign(sign)),
2134 },
2135 width: map_width(width)?,
2136 });
2137 self.lookup_type.insert(
2138 id,
2139 LookupType {
2140 handle: module.types.insert(
2141 crate::Type {
2142 name: self.future_decor.remove(&id).and_then(|dec| dec.name),
2143 inner,
2144 },
2145 self.span_from_with_op(start),
2146 ),
2147 base_id: None,
2148 },
2149 );
2150 Ok(())
2151 }
2152
2153 fn parse_type_float(
2154 &mut self,
2155 inst: Instruction,
2156 module: &mut crate::Module,
2157 ) -> Result<(), Error> {
2158 let start = self.data_offset;
2159 self.switch(ModuleState::Type, inst.op)?;
2160 inst.expect(3)?;
2161 let id = self.next()?;
2162 let width = self.next()?;
2163 let inner = crate::TypeInner::Scalar(crate::Scalar::float(map_width(width)?));
2164 self.lookup_type.insert(
2165 id,
2166 LookupType {
2167 handle: module.types.insert(
2168 crate::Type {
2169 name: self.future_decor.remove(&id).and_then(|dec| dec.name),
2170 inner,
2171 },
2172 self.span_from_with_op(start),
2173 ),
2174 base_id: None,
2175 },
2176 );
2177 Ok(())
2178 }
2179
2180 fn parse_type_vector(
2181 &mut self,
2182 inst: Instruction,
2183 module: &mut crate::Module,
2184 ) -> Result<(), Error> {
2185 let start = self.data_offset;
2186 self.switch(ModuleState::Type, inst.op)?;
2187 inst.expect(4)?;
2188 let id = self.next()?;
2189 let type_id = self.next()?;
2190 let type_lookup = self.lookup_type.lookup(type_id)?;
2191 let scalar = match module.types[type_lookup.handle].inner {
2192 crate::TypeInner::Scalar(scalar) => scalar,
2193 _ => return Err(Error::InvalidInnerType(type_id)),
2194 };
2195 let component_count = self.next()?;
2196 let inner = crate::TypeInner::Vector {
2197 size: map_vector_size(component_count)?,
2198 scalar,
2199 };
2200 self.lookup_type.insert(
2201 id,
2202 LookupType {
2203 handle: module.types.insert(
2204 crate::Type {
2205 name: self.future_decor.remove(&id).and_then(|dec| dec.name),
2206 inner,
2207 },
2208 self.span_from_with_op(start),
2209 ),
2210 base_id: Some(type_id),
2211 },
2212 );
2213 Ok(())
2214 }
2215
2216 fn parse_type_matrix(
2217 &mut self,
2218 inst: Instruction,
2219 module: &mut crate::Module,
2220 ) -> Result<(), Error> {
2221 let start = self.data_offset;
2222 self.switch(ModuleState::Type, inst.op)?;
2223 inst.expect(4)?;
2224 let id = self.next()?;
2225 let vector_type_id = self.next()?;
2226 let num_columns = self.next()?;
2227 let decor = self.future_decor.remove(&id);
2228
2229 let vector_type_lookup = self.lookup_type.lookup(vector_type_id)?;
2230 let inner = match module.types[vector_type_lookup.handle].inner {
2231 crate::TypeInner::Vector { size, scalar } => crate::TypeInner::Matrix {
2232 columns: map_vector_size(num_columns)?,
2233 rows: size,
2234 scalar,
2235 },
2236 _ => return Err(Error::InvalidInnerType(vector_type_id)),
2237 };
2238
2239 self.lookup_type.insert(
2240 id,
2241 LookupType {
2242 handle: module.types.insert(
2243 crate::Type {
2244 name: decor.and_then(|dec| dec.name),
2245 inner,
2246 },
2247 self.span_from_with_op(start),
2248 ),
2249 base_id: Some(vector_type_id),
2250 },
2251 );
2252 Ok(())
2253 }
2254
2255 fn parse_type_function(&mut self, inst: Instruction) -> Result<(), Error> {
2256 self.switch(ModuleState::Type, inst.op)?;
2257 inst.expect_at_least(3)?;
2258 let id = self.next()?;
2259 let return_type_id = self.next()?;
2260 let parameter_type_ids = self.data.by_ref().take(inst.wc as usize - 3).collect();
2261 self.lookup_function_type.insert(
2262 id,
2263 LookupFunctionType {
2264 parameter_type_ids,
2265 return_type_id,
2266 },
2267 );
2268 Ok(())
2269 }
2270
2271 fn parse_type_pointer(
2272 &mut self,
2273 inst: Instruction,
2274 module: &mut crate::Module,
2275 ) -> Result<(), Error> {
2276 let start = self.data_offset;
2277 self.switch(ModuleState::Type, inst.op)?;
2278 inst.expect(4)?;
2279 let id = self.next()?;
2280 let storage_class = self.next()?;
2281 let type_id = self.next()?;
2282
2283 let decor = self.future_decor.remove(&id);
2284 let base_lookup_ty = self.lookup_type.lookup(type_id)?;
2285 let base_inner = &module.types[base_lookup_ty.handle].inner;
2286
2287 let space = if let Some(space) = base_inner.pointer_space() {
2288 space
2289 } else if self
2290 .lookup_storage_buffer_types
2291 .contains_key(&base_lookup_ty.handle)
2292 {
2293 crate::AddressSpace::Storage {
2294 access: crate::StorageAccess::default(),
2295 }
2296 } else {
2297 match map_storage_class(storage_class)? {
2298 ExtendedClass::Global(space) => space,
2299 ExtendedClass::Input | ExtendedClass::Output => crate::AddressSpace::Private,
2300 }
2301 };
2302
2303 if let crate::TypeInner::Array {
2307 size: crate::ArraySize::Dynamic,
2308 ..
2309 } = *base_inner
2310 {
2311 match space {
2312 crate::AddressSpace::Storage { .. } => {}
2313 _ => {
2314 return Err(Error::UnsupportedRuntimeArrayStorageClass);
2315 }
2316 }
2317 }
2318
2319 let lookup_ty = if space == crate::AddressSpace::Handle {
2321 base_lookup_ty.clone()
2322 } else {
2323 LookupType {
2324 handle: module.types.insert(
2325 crate::Type {
2326 name: decor.and_then(|dec| dec.name),
2327 inner: crate::TypeInner::Pointer {
2328 base: base_lookup_ty.handle,
2329 space,
2330 },
2331 },
2332 self.span_from_with_op(start),
2333 ),
2334 base_id: Some(type_id),
2335 }
2336 };
2337 self.lookup_type.insert(id, lookup_ty);
2338 Ok(())
2339 }
2340
2341 fn parse_type_array(
2342 &mut self,
2343 inst: Instruction,
2344 module: &mut crate::Module,
2345 ) -> Result<(), Error> {
2346 let start = self.data_offset;
2347 self.switch(ModuleState::Type, inst.op)?;
2348 inst.expect(4)?;
2349 let id = self.next()?;
2350 let type_id = self.next()?;
2351 let length_id = self.next()?;
2352 let length_const = self.lookup_constant.lookup(length_id)?;
2353
2354 let size = resolve_constant(module.to_ctx(), &length_const.inner)
2355 .and_then(NonZeroU32::new)
2356 .ok_or(Error::InvalidArraySize(length_id))?;
2357
2358 let decor = self.future_decor.remove(&id).unwrap_or_default();
2359 let base = self.lookup_type.lookup(type_id)?.handle;
2360
2361 self.layouter.update(module.to_ctx()).unwrap();
2362
2363 let inner = if let crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } =
2395 module.types[base].inner
2396 {
2397 crate::TypeInner::BindingArray {
2398 base,
2399 size: crate::ArraySize::Constant(size),
2400 }
2401 } else {
2402 crate::TypeInner::Array {
2403 base,
2404 size: crate::ArraySize::Constant(size),
2405 stride: match decor.array_stride {
2406 Some(stride) => stride.get(),
2407 None => self.layouter[base].to_stride(),
2408 },
2409 }
2410 };
2411
2412 self.lookup_type.insert(
2413 id,
2414 LookupType {
2415 handle: module.types.insert(
2416 crate::Type {
2417 name: decor.name,
2418 inner,
2419 },
2420 self.span_from_with_op(start),
2421 ),
2422 base_id: Some(type_id),
2423 },
2424 );
2425 Ok(())
2426 }
2427
2428 fn parse_type_runtime_array(
2429 &mut self,
2430 inst: Instruction,
2431 module: &mut crate::Module,
2432 ) -> Result<(), Error> {
2433 let start = self.data_offset;
2434 self.switch(ModuleState::Type, inst.op)?;
2435 inst.expect(3)?;
2436 let id = self.next()?;
2437 let type_id = self.next()?;
2438
2439 let decor = self.future_decor.remove(&id).unwrap_or_default();
2440 let base = self.lookup_type.lookup(type_id)?.handle;
2441
2442 self.layouter.update(module.to_ctx()).unwrap();
2443
2444 let inner = if let crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } =
2446 module.types[base].inner
2447 {
2448 crate::TypeInner::BindingArray {
2449 base: self.lookup_type.lookup(type_id)?.handle,
2450 size: crate::ArraySize::Dynamic,
2451 }
2452 } else {
2453 crate::TypeInner::Array {
2454 base: self.lookup_type.lookup(type_id)?.handle,
2455 size: crate::ArraySize::Dynamic,
2456 stride: match decor.array_stride {
2457 Some(stride) => stride.get(),
2458 None => self.layouter[base].to_stride(),
2459 },
2460 }
2461 };
2462
2463 self.lookup_type.insert(
2464 id,
2465 LookupType {
2466 handle: module.types.insert(
2467 crate::Type {
2468 name: decor.name,
2469 inner,
2470 },
2471 self.span_from_with_op(start),
2472 ),
2473 base_id: Some(type_id),
2474 },
2475 );
2476 Ok(())
2477 }
2478
2479 fn parse_type_struct(
2480 &mut self,
2481 inst: Instruction,
2482 module: &mut crate::Module,
2483 ) -> Result<(), Error> {
2484 let start = self.data_offset;
2485 self.switch(ModuleState::Type, inst.op)?;
2486 inst.expect_at_least(2)?;
2487 let id = self.next()?;
2488 let parent_decor = self.future_decor.remove(&id);
2489 let is_storage_buffer = parent_decor
2490 .as_ref()
2491 .is_some_and(|decor| decor.storage_buffer);
2492
2493 self.layouter.update(module.to_ctx()).unwrap();
2494
2495 let mut members = Vec::<crate::StructMember>::with_capacity(inst.wc as usize - 2);
2496 let mut member_lookups = Vec::with_capacity(members.capacity());
2497 let mut storage_access = crate::StorageAccess::empty();
2498 let mut span = 0;
2499 let mut alignment = Alignment::ONE;
2500 for i in 0..u32::from(inst.wc) - 2 {
2501 let type_id = self.next()?;
2502 let ty = self.lookup_type.lookup(type_id)?.handle;
2503 let decor = self
2504 .future_member_decor
2505 .remove(&(id, i))
2506 .unwrap_or_default();
2507
2508 storage_access |= decor.flags.to_storage_access();
2509
2510 member_lookups.push(LookupMember {
2511 type_id,
2512 row_major: decor.matrix_major == Some(Majority::Row),
2513 });
2514
2515 let member_alignment = self.layouter[ty].alignment;
2516 span = member_alignment.round_up(span);
2517 alignment = member_alignment.max(alignment);
2518
2519 let binding = decor.io_binding().ok();
2520 if let Some(offset) = decor.offset {
2521 span = offset;
2522 }
2523 let offset = span;
2524
2525 span += self.layouter[ty].size;
2526
2527 let inner = &module.types[ty].inner;
2528 if let crate::TypeInner::Matrix {
2529 columns,
2530 rows,
2531 scalar,
2532 } = *inner
2533 {
2534 if let Some(stride) = decor.matrix_stride {
2535 let expected_stride = Alignment::from(rows) * scalar.width as u32;
2536 if stride.get() != expected_stride {
2537 return Err(Error::UnsupportedMatrixStride {
2538 stride: stride.get(),
2539 columns: columns as u8,
2540 rows: rows as u8,
2541 width: scalar.width,
2542 });
2543 }
2544 }
2545 }
2546
2547 members.push(crate::StructMember {
2548 name: decor.name,
2549 ty,
2550 binding,
2551 offset,
2552 });
2553 }
2554
2555 span = alignment.round_up(span);
2556
2557 let inner = crate::TypeInner::Struct { span, members };
2558
2559 let ty_handle = module.types.insert(
2560 crate::Type {
2561 name: parent_decor.and_then(|dec| dec.name),
2562 inner,
2563 },
2564 self.span_from_with_op(start),
2565 );
2566
2567 if is_storage_buffer {
2568 self.lookup_storage_buffer_types
2569 .insert(ty_handle, storage_access);
2570 }
2571 for (i, member_lookup) in member_lookups.into_iter().enumerate() {
2572 self.lookup_member
2573 .insert((ty_handle, i as u32), member_lookup);
2574 }
2575 self.lookup_type.insert(
2576 id,
2577 LookupType {
2578 handle: ty_handle,
2579 base_id: None,
2580 },
2581 );
2582 Ok(())
2583 }
2584
2585 fn parse_type_image(
2586 &mut self,
2587 inst: Instruction,
2588 module: &mut crate::Module,
2589 ) -> Result<(), Error> {
2590 let start = self.data_offset;
2591 self.switch(ModuleState::Type, inst.op)?;
2592 inst.expect(9)?;
2593
2594 let id = self.next()?;
2595 let sample_type_id = self.next()?;
2596 let dim = self.next()?;
2597 let is_depth = self.next()?;
2598 let is_array = self.next()? != 0;
2599 let is_msaa = self.next()? != 0;
2600 let is_sampled = self.next()?;
2601 let format = self.next()?;
2602
2603 let dim = map_image_dim(dim)?;
2604 let decor = self.future_decor.remove(&id).unwrap_or_default();
2605
2606 module.types.insert(
2608 crate::Type {
2609 name: None,
2610 inner: {
2611 let scalar = crate::Scalar::F32;
2612 match dim.required_coordinate_size() {
2613 None => crate::TypeInner::Scalar(scalar),
2614 Some(size) => crate::TypeInner::Vector { size, scalar },
2615 }
2616 },
2617 },
2618 Default::default(),
2619 );
2620
2621 let base_handle = self.lookup_type.lookup(sample_type_id)?.handle;
2622 let kind = module.types[base_handle]
2623 .inner
2624 .scalar_kind()
2625 .ok_or(Error::InvalidImageBaseType(base_handle))?;
2626
2627 let inner = crate::TypeInner::Image {
2628 class: if is_depth == 1 {
2629 crate::ImageClass::Depth { multi: is_msaa }
2630 } else if format != 0 {
2631 crate::ImageClass::Storage {
2632 format: map_image_format(format)?,
2633 access: crate::StorageAccess::default(),
2634 }
2635 } else if is_sampled == 2 {
2636 return Err(Error::InvalidImageWriteType);
2637 } else {
2638 crate::ImageClass::Sampled {
2639 kind,
2640 multi: is_msaa,
2641 }
2642 },
2643 dim,
2644 arrayed: is_array,
2645 };
2646
2647 let handle = module.types.insert(
2648 crate::Type {
2649 name: decor.name,
2650 inner,
2651 },
2652 self.span_from_with_op(start),
2653 );
2654
2655 self.lookup_type.insert(
2656 id,
2657 LookupType {
2658 handle,
2659 base_id: Some(sample_type_id),
2660 },
2661 );
2662 Ok(())
2663 }
2664
2665 fn parse_type_sampled_image(&mut self, inst: Instruction) -> Result<(), Error> {
2666 self.switch(ModuleState::Type, inst.op)?;
2667 inst.expect(3)?;
2668 let id = self.next()?;
2669 let image_id = self.next()?;
2670 self.lookup_type.insert(
2671 id,
2672 LookupType {
2673 handle: self.lookup_type.lookup(image_id)?.handle,
2674 base_id: Some(image_id),
2675 },
2676 );
2677 Ok(())
2678 }
2679
2680 fn parse_type_sampler(
2681 &mut self,
2682 inst: Instruction,
2683 module: &mut crate::Module,
2684 ) -> Result<(), Error> {
2685 let start = self.data_offset;
2686 self.switch(ModuleState::Type, inst.op)?;
2687 inst.expect(2)?;
2688 let id = self.next()?;
2689 let decor = self.future_decor.remove(&id).unwrap_or_default();
2690 let handle = module.types.insert(
2691 crate::Type {
2692 name: decor.name,
2693 inner: crate::TypeInner::Sampler { comparison: false },
2694 },
2695 self.span_from_with_op(start),
2696 );
2697 self.lookup_type.insert(
2698 id,
2699 LookupType {
2700 handle,
2701 base_id: None,
2702 },
2703 );
2704 Ok(())
2705 }
2706
2707 fn parse_constant(
2708 &mut self,
2709 inst: Instruction,
2710 module: &mut crate::Module,
2711 ) -> Result<(), Error> {
2712 let start = self.data_offset;
2713 self.switch(ModuleState::Type, inst.op)?;
2714 inst.expect_at_least(4)?;
2715 let type_id = self.next()?;
2716 let id = self.next()?;
2717 let type_lookup = self.lookup_type.lookup(type_id)?;
2718 let ty = type_lookup.handle;
2719
2720 let literal = match module.types[ty].inner {
2721 crate::TypeInner::Scalar(crate::Scalar {
2722 kind: crate::ScalarKind::Uint,
2723 width,
2724 }) => {
2725 let low = self.next()?;
2726 match width {
2727 4 => crate::Literal::U32(low),
2728 8 => {
2729 inst.expect(5)?;
2730 let high = self.next()?;
2731 crate::Literal::U64((u64::from(high) << 32) | u64::from(low))
2732 }
2733 _ => return Err(Error::InvalidTypeWidth(width as u32)),
2734 }
2735 }
2736 crate::TypeInner::Scalar(crate::Scalar {
2737 kind: crate::ScalarKind::Sint,
2738 width,
2739 }) => {
2740 let low = self.next()?;
2741 match width {
2742 4 => crate::Literal::I32(low as i32),
2743 8 => {
2744 inst.expect(5)?;
2745 let high = self.next()?;
2746 crate::Literal::I64(((u64::from(high) << 32) | u64::from(low)) as i64)
2747 }
2748 _ => return Err(Error::InvalidTypeWidth(width as u32)),
2749 }
2750 }
2751 crate::TypeInner::Scalar(crate::Scalar {
2752 kind: crate::ScalarKind::Float,
2753 width,
2754 }) => {
2755 let low = self.next()?;
2756 match width {
2757 2 => crate::Literal::F16(f16::from_bits(low as u16)),
2760 4 => crate::Literal::F32(f32::from_bits(low)),
2761 8 => {
2762 inst.expect(5)?;
2763 let high = self.next()?;
2764 crate::Literal::F64(f64::from_bits(
2765 (u64::from(high) << 32) | u64::from(low),
2766 ))
2767 }
2768 _ => return Err(Error::InvalidTypeWidth(width as u32)),
2769 }
2770 }
2771 _ => return Err(Error::UnsupportedType(type_lookup.handle)),
2772 };
2773
2774 let span = self.span_from_with_op(start);
2775
2776 let init = module
2777 .global_expressions
2778 .append(crate::Expression::Literal(literal), span);
2779
2780 self.insert_parsed_constant(module, id, type_id, ty, init, span)
2781 }
2782
2783 fn parse_composite_constant(
2784 &mut self,
2785 inst: Instruction,
2786 module: &mut crate::Module,
2787 ) -> Result<(), Error> {
2788 let start = self.data_offset;
2789 self.switch(ModuleState::Type, inst.op)?;
2790 inst.expect_at_least(3)?;
2791 let type_id = self.next()?;
2792 let id = self.next()?;
2793
2794 let type_lookup = self.lookup_type.lookup(type_id)?;
2795 let ty = type_lookup.handle;
2796
2797 let mut components = Vec::with_capacity(inst.wc as usize - 3);
2798 for _ in 0..components.capacity() {
2799 let start = self.data_offset;
2800 let component_id = self.next()?;
2801 let span = self.span_from_with_op(start);
2802 let constant = self.lookup_constant.lookup(component_id)?;
2803 let expr = module
2804 .global_expressions
2805 .append(constant.inner.to_expr(), span);
2806 components.push(expr);
2807 }
2808
2809 let span = self.span_from_with_op(start);
2810
2811 let init = module
2812 .global_expressions
2813 .append(crate::Expression::Compose { ty, components }, span);
2814
2815 self.insert_parsed_constant(module, id, type_id, ty, init, span)
2816 }
2817
2818 fn parse_null_constant(
2819 &mut self,
2820 inst: Instruction,
2821 module: &mut crate::Module,
2822 ) -> Result<(), Error> {
2823 let start = self.data_offset;
2824 self.switch(ModuleState::Type, inst.op)?;
2825 inst.expect(3)?;
2826 let type_id = self.next()?;
2827 let id = self.next()?;
2828 let span = self.span_from_with_op(start);
2829
2830 let type_lookup = self.lookup_type.lookup(type_id)?;
2831 let ty = type_lookup.handle;
2832
2833 let init = module
2834 .global_expressions
2835 .append(crate::Expression::ZeroValue(ty), span);
2836
2837 self.insert_parsed_constant(module, id, type_id, ty, init, span)
2838 }
2839
2840 fn parse_bool_constant(
2841 &mut self,
2842 inst: Instruction,
2843 value: bool,
2844 module: &mut crate::Module,
2845 ) -> Result<(), Error> {
2846 let start = self.data_offset;
2847 self.switch(ModuleState::Type, inst.op)?;
2848 inst.expect(3)?;
2849 let type_id = self.next()?;
2850 let id = self.next()?;
2851 let span = self.span_from_with_op(start);
2852
2853 let type_lookup = self.lookup_type.lookup(type_id)?;
2854 let ty = type_lookup.handle;
2855
2856 let init = module.global_expressions.append(
2857 crate::Expression::Literal(crate::Literal::Bool(value)),
2858 span,
2859 );
2860
2861 self.insert_parsed_constant(module, id, type_id, ty, init, span)
2862 }
2863
2864 fn insert_parsed_constant(
2865 &mut self,
2866 module: &mut crate::Module,
2867 id: u32,
2868 type_id: u32,
2869 ty: Handle<crate::Type>,
2870 init: Handle<crate::Expression>,
2871 span: crate::Span,
2872 ) -> Result<(), Error> {
2873 let decor = self.future_decor.remove(&id).unwrap_or_default();
2874
2875 let inner = if let Some(id) = decor.specialization_constant_id {
2876 let o = crate::Override {
2877 name: decor.name,
2878 id: Some(id.try_into().map_err(|_| Error::SpecIdTooHigh(id))?),
2879 ty,
2880 init: Some(init),
2881 };
2882 Constant::Override(module.overrides.append(o, span))
2883 } else {
2884 let c = crate::Constant {
2885 name: decor.name,
2886 ty,
2887 init,
2888 };
2889 Constant::Constant(module.constants.append(c, span))
2890 };
2891
2892 self.lookup_constant
2893 .insert(id, LookupConstant { inner, type_id });
2894 Ok(())
2895 }
2896
2897 fn parse_global_variable(
2898 &mut self,
2899 inst: Instruction,
2900 module: &mut crate::Module,
2901 ) -> Result<(), Error> {
2902 let start = self.data_offset;
2903 self.switch(ModuleState::Type, inst.op)?;
2904 inst.expect_at_least(4)?;
2905 let type_id = self.next()?;
2906 let id = self.next()?;
2907 let storage_class = self.next()?;
2908 let init = if inst.wc > 4 {
2909 inst.expect(5)?;
2910 let start = self.data_offset;
2911 let init_id = self.next()?;
2912 let span = self.span_from_with_op(start);
2913 let lconst = self.lookup_constant.lookup(init_id)?;
2914 let expr = module
2915 .global_expressions
2916 .append(lconst.inner.to_expr(), span);
2917 Some(expr)
2918 } else {
2919 None
2920 };
2921 let span = self.span_from_with_op(start);
2922 let dec = self.future_decor.remove(&id).unwrap_or_default();
2923
2924 let original_ty = self.lookup_type.lookup(type_id)?.handle;
2925 let mut ty = original_ty;
2926
2927 if let crate::TypeInner::Pointer { base, space: _ } = module.types[original_ty].inner {
2928 ty = base;
2929 }
2930
2931 if let crate::TypeInner::BindingArray { .. } = module.types[original_ty].inner {
2932 if dec.desc_set.is_none() || dec.desc_index.is_none() {
2935 return Err(Error::NonBindingArrayOfImageOrSamplers);
2936 }
2937 }
2938
2939 if let crate::TypeInner::Image {
2940 dim,
2941 arrayed,
2942 class: crate::ImageClass::Storage { format, access: _ },
2943 } = module.types[ty].inner
2944 {
2945 let access = dec.flags.to_storage_access();
2949
2950 ty = module.types.insert(
2951 crate::Type {
2952 name: None,
2953 inner: crate::TypeInner::Image {
2954 dim,
2955 arrayed,
2956 class: crate::ImageClass::Storage { format, access },
2957 },
2958 },
2959 Default::default(),
2960 );
2961 }
2962
2963 let ext_class = match self.lookup_storage_buffer_types.get(&ty) {
2964 Some(&access) => ExtendedClass::Global(crate::AddressSpace::Storage { access }),
2965 None => map_storage_class(storage_class)?,
2966 };
2967
2968 let (inner, var) = match ext_class {
2969 ExtendedClass::Global(mut space) => {
2970 if let crate::AddressSpace::Storage { ref mut access } = space {
2971 *access &= dec.flags.to_storage_access();
2972 }
2973 let var = crate::GlobalVariable {
2974 binding: dec.resource_binding(),
2975 name: dec.name,
2976 space,
2977 ty,
2978 init,
2979 };
2980 (Variable::Global, var)
2981 }
2982 ExtendedClass::Input => {
2983 let binding = dec.io_binding()?;
2984 let mut unsigned_ty = ty;
2985 if let crate::Binding::BuiltIn(built_in) = binding {
2986 let needs_inner_uint = match built_in {
2987 crate::BuiltIn::BaseInstance
2988 | crate::BuiltIn::BaseVertex
2989 | crate::BuiltIn::InstanceIndex
2990 | crate::BuiltIn::SampleIndex
2991 | crate::BuiltIn::VertexIndex
2992 | crate::BuiltIn::PrimitiveIndex
2993 | crate::BuiltIn::LocalInvocationIndex => {
2994 Some(crate::TypeInner::Scalar(crate::Scalar::U32))
2995 }
2996 crate::BuiltIn::GlobalInvocationId
2997 | crate::BuiltIn::LocalInvocationId
2998 | crate::BuiltIn::WorkGroupId
2999 | crate::BuiltIn::WorkGroupSize => Some(crate::TypeInner::Vector {
3000 size: crate::VectorSize::Tri,
3001 scalar: crate::Scalar::U32,
3002 }),
3003 crate::BuiltIn::Barycentric { perspective: false } => {
3004 Some(crate::TypeInner::Vector {
3005 size: crate::VectorSize::Tri,
3006 scalar: crate::Scalar::F32,
3007 })
3008 }
3009 _ => None,
3010 };
3011 if let (Some(inner), Some(crate::ScalarKind::Sint)) =
3012 (needs_inner_uint, module.types[ty].inner.scalar_kind())
3013 {
3014 unsigned_ty = module
3015 .types
3016 .insert(crate::Type { name: None, inner }, Default::default());
3017 }
3018 }
3019
3020 let var = crate::GlobalVariable {
3021 name: dec.name.clone(),
3022 space: crate::AddressSpace::Private,
3023 binding: None,
3024 ty,
3025 init: None,
3026 };
3027
3028 let inner = Variable::Input(crate::FunctionArgument {
3029 name: dec.name,
3030 ty: unsigned_ty,
3031 binding: Some(binding),
3032 });
3033 (inner, var)
3034 }
3035 ExtendedClass::Output => {
3036 let binding = dec.io_binding().ok();
3038 let init = match binding {
3039 Some(crate::Binding::BuiltIn(built_in)) => {
3040 match null::generate_default_built_in(
3041 Some(built_in),
3042 ty,
3043 &mut module.global_expressions,
3044 span,
3045 ) {
3046 Ok(handle) => Some(handle),
3047 Err(e) => {
3048 log::warn!("Failed to initialize output built-in: {e}");
3049 None
3050 }
3051 }
3052 }
3053 Some(crate::Binding::Location { .. }) => None,
3054 None => match module.types[ty].inner {
3055 crate::TypeInner::Struct { ref members, .. } => {
3056 let mut components = Vec::with_capacity(members.len());
3057 for member in members.iter() {
3058 let built_in = match member.binding {
3059 Some(crate::Binding::BuiltIn(built_in)) => Some(built_in),
3060 _ => None,
3061 };
3062 let handle = null::generate_default_built_in(
3063 built_in,
3064 member.ty,
3065 &mut module.global_expressions,
3066 span,
3067 )?;
3068 components.push(handle);
3069 }
3070 Some(
3071 module
3072 .global_expressions
3073 .append(crate::Expression::Compose { ty, components }, span),
3074 )
3075 }
3076 _ => None,
3077 },
3078 };
3079
3080 let var = crate::GlobalVariable {
3081 name: dec.name,
3082 space: crate::AddressSpace::Private,
3083 binding: None,
3084 ty,
3085 init,
3086 };
3087 let inner = Variable::Output(crate::FunctionResult { ty, binding });
3088 (inner, var)
3089 }
3090 };
3091
3092 let handle = module.global_variables.append(var, span);
3093
3094 if module.types[ty].inner.can_comparison_sample(module) {
3095 log::debug!("\t\ttracking {handle:?} for sampling properties");
3096
3097 self.handle_sampling
3098 .insert(handle, image::SamplingFlags::empty());
3099 }
3100
3101 self.lookup_variable.insert(
3102 id,
3103 LookupVariable {
3104 inner,
3105 handle,
3106 type_id,
3107 },
3108 );
3109 Ok(())
3110 }
3111
3112 fn record_atomic_access(
3125 &mut self,
3126 ctx: &BlockContext,
3127 handle: Handle<crate::Expression>,
3128 ) -> Result<Handle<crate::Type>, Error> {
3129 log::debug!("\t\tlocating global variable in {handle:?}");
3130 match ctx.expressions[handle] {
3131 crate::Expression::Access { base, index } => {
3132 log::debug!("\t\t access {handle:?} {index:?}");
3133 let ty = self.record_atomic_access(ctx, base)?;
3134 let crate::TypeInner::Array { base, .. } = ctx.module.types[ty].inner else {
3135 unreachable!("Atomic operations on Access expressions only work for arrays");
3136 };
3137 Ok(base)
3138 }
3139 crate::Expression::AccessIndex { base, index } => {
3140 log::debug!("\t\t access index {handle:?} {index:?}");
3141 let ty = self.record_atomic_access(ctx, base)?;
3142 match ctx.module.types[ty].inner {
3143 crate::TypeInner::Struct { ref members, .. } => {
3144 let index = index as usize;
3145 self.upgrade_atomics.insert_field(ty, index);
3146 Ok(members[index].ty)
3147 }
3148 crate::TypeInner::Array { base, .. } => {
3149 Ok(base)
3150 }
3151 _ => unreachable!("Atomic operations on AccessIndex expressions only work for structs and arrays"),
3152 }
3153 }
3154 crate::Expression::GlobalVariable(h) => {
3155 log::debug!("\t\t found {h:?}");
3156 self.upgrade_atomics.insert_global(h);
3157 Ok(ctx.module.global_variables[h].ty)
3158 }
3159 _ => Err(Error::AtomicUpgradeError(
3160 crate::front::atomic_upgrade::Error::GlobalVariableMissing,
3161 )),
3162 }
3163 }
3164}
3165
3166fn resolve_constant(gctx: crate::proc::GlobalCtx, constant: &Constant) -> Option<u32> {
3167 let constant = match *constant {
3168 Constant::Constant(constant) => constant,
3169 Constant::Override(_) => return None,
3170 };
3171 match gctx.global_expressions[gctx.constants[constant].init] {
3172 crate::Expression::Literal(crate::Literal::U32(id)) => Some(id),
3173 crate::Expression::Literal(crate::Literal::I32(id)) => Some(id as u32),
3174 _ => None,
3175 }
3176}
3177
3178pub fn parse_u8_slice(data: &[u8], options: &Options) -> Result<crate::Module, Error> {
3179 if data.len() % 4 != 0 {
3180 return Err(Error::IncompleteData);
3181 }
3182
3183 let words = data
3184 .chunks(4)
3185 .map(|c| u32::from_le_bytes(c.try_into().unwrap()));
3186 Frontend::new(words, options).parse()
3187}
3188
3189fn is_parent(mut child: usize, parent: usize, block_ctx: &BlockContext) -> bool {
3191 loop {
3192 if child == parent {
3193 break true;
3195 } else if child == 0 {
3196 break false;
3198 }
3199
3200 child = block_ctx.bodies[child].parent;
3201 }
3202}
3203
3204#[cfg(test)]
3205mod test {
3206 use alloc::vec;
3207
3208 #[test]
3209 fn parse() {
3210 let bin = vec![
3211 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00,
3213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3218 ];
3219 let _ = super::parse_u8_slice(&bin, &Default::default()).unwrap();
3220 }
3221}