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