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