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