naga/back/spv/
instructions.rs

1use alloc::{vec, vec::Vec};
2
3use spirv::{Op, Word};
4
5use super::{block::DebugInfoInner, helpers};
6
7pub(super) enum Signedness {
8    Unsigned = 0,
9    Signed = 1,
10}
11
12pub(super) enum SampleLod {
13    Explicit,
14    Implicit,
15}
16
17pub(super) struct Case {
18    pub value: Word,
19    pub label_id: Word,
20}
21
22impl super::Instruction {
23    //
24    //  Debug Instructions
25    //
26
27    pub(super) fn string(name: &str, id: Word) -> Self {
28        let mut instruction = Self::new(Op::String);
29        instruction.set_result(id);
30        instruction.add_operands(helpers::string_to_words(name));
31        instruction
32    }
33
34    pub(super) fn source(
35        source_language: spirv::SourceLanguage,
36        version: u32,
37        source: &Option<DebugInfoInner>,
38    ) -> Self {
39        let mut instruction = Self::new(Op::Source);
40        instruction.add_operand(source_language as u32);
41        instruction.add_operands(helpers::bytes_to_words(&version.to_le_bytes()));
42        if let Some(source) = source.as_ref() {
43            instruction.add_operand(source.source_file_id);
44            instruction.add_operands(helpers::string_to_words(source.source_code));
45        }
46        instruction
47    }
48
49    pub(super) fn source_continued(source: &[u8]) -> Self {
50        let mut instruction = Self::new(Op::SourceContinued);
51        instruction.add_operands(helpers::str_bytes_to_words(source));
52        instruction
53    }
54
55    pub(super) fn source_auto_continued(
56        source_language: spirv::SourceLanguage,
57        version: u32,
58        source: &Option<DebugInfoInner>,
59    ) -> Vec<Self> {
60        let mut instructions = vec![];
61
62        let with_continue = source.as_ref().and_then(|debug_info| {
63            (debug_info.source_code.len() > u16::MAX as usize).then_some(debug_info)
64        });
65        if let Some(debug_info) = with_continue {
66            let mut instruction = Self::new(Op::Source);
67            instruction.add_operand(source_language as u32);
68            instruction.add_operands(helpers::bytes_to_words(&version.to_le_bytes()));
69
70            let words = helpers::string_to_byte_chunks(debug_info.source_code, u16::MAX as usize);
71            instruction.add_operand(debug_info.source_file_id);
72            instruction.add_operands(helpers::str_bytes_to_words(words[0]));
73            instructions.push(instruction);
74            for word_bytes in words[1..].iter() {
75                let instruction_continue = Self::source_continued(word_bytes);
76                instructions.push(instruction_continue);
77            }
78        } else {
79            let instruction = Self::source(source_language, version, source);
80            instructions.push(instruction);
81        }
82        instructions
83    }
84
85    pub(super) fn name(target_id: Word, name: &str) -> Self {
86        let mut instruction = Self::new(Op::Name);
87        instruction.add_operand(target_id);
88        instruction.add_operands(helpers::string_to_words(name));
89        instruction
90    }
91
92    pub(super) fn member_name(target_id: Word, member: Word, name: &str) -> Self {
93        let mut instruction = Self::new(Op::MemberName);
94        instruction.add_operand(target_id);
95        instruction.add_operand(member);
96        instruction.add_operands(helpers::string_to_words(name));
97        instruction
98    }
99
100    pub(super) fn line(file: Word, line: Word, column: Word) -> Self {
101        let mut instruction = Self::new(Op::Line);
102        instruction.add_operand(file);
103        instruction.add_operand(line);
104        instruction.add_operand(column);
105        instruction
106    }
107
108    //
109    //  Annotation Instructions
110    //
111
112    pub(super) fn decorate(
113        target_id: Word,
114        decoration: spirv::Decoration,
115        operands: &[Word],
116    ) -> Self {
117        let mut instruction = Self::new(Op::Decorate);
118        instruction.add_operand(target_id);
119        instruction.add_operand(decoration as u32);
120        for operand in operands {
121            instruction.add_operand(*operand)
122        }
123        instruction
124    }
125
126    pub(super) fn member_decorate(
127        target_id: Word,
128        member_index: Word,
129        decoration: spirv::Decoration,
130        operands: &[Word],
131    ) -> Self {
132        let mut instruction = Self::new(Op::MemberDecorate);
133        instruction.add_operand(target_id);
134        instruction.add_operand(member_index);
135        instruction.add_operand(decoration as u32);
136        for operand in operands {
137            instruction.add_operand(*operand)
138        }
139        instruction
140    }
141
142    //
143    //  Extension Instructions
144    //
145
146    pub(super) fn extension(name: &str) -> Self {
147        let mut instruction = Self::new(Op::Extension);
148        instruction.add_operands(helpers::string_to_words(name));
149        instruction
150    }
151
152    pub(super) fn ext_inst_import(id: Word, name: &str) -> Self {
153        let mut instruction = Self::new(Op::ExtInstImport);
154        instruction.set_result(id);
155        instruction.add_operands(helpers::string_to_words(name));
156        instruction
157    }
158
159    pub(super) fn ext_inst_gl_op(
160        set_id: Word,
161        op: spirv::GLOp,
162        result_type_id: Word,
163        id: Word,
164        operands: &[Word],
165    ) -> Self {
166        Self::ext_inst(set_id, op as u32, result_type_id, id, operands)
167    }
168
169    pub(super) fn ext_inst(
170        set_id: Word,
171        op: u32,
172        result_type_id: Word,
173        id: Word,
174        operands: &[Word],
175    ) -> Self {
176        let mut instruction = Self::new(Op::ExtInst);
177        instruction.set_type(result_type_id);
178        instruction.set_result(id);
179        instruction.add_operand(set_id);
180        instruction.add_operand(op);
181        for operand in operands {
182            instruction.add_operand(*operand)
183        }
184        instruction
185    }
186
187    //
188    //  Mode-Setting Instructions
189    //
190
191    pub(super) fn memory_model(
192        addressing_model: spirv::AddressingModel,
193        memory_model: spirv::MemoryModel,
194    ) -> Self {
195        let mut instruction = Self::new(Op::MemoryModel);
196        instruction.add_operand(addressing_model as u32);
197        instruction.add_operand(memory_model as u32);
198        instruction
199    }
200
201    pub(super) fn entry_point(
202        execution_model: spirv::ExecutionModel,
203        entry_point_id: Word,
204        name: &str,
205        interface_ids: &[Word],
206    ) -> Self {
207        let mut instruction = Self::new(Op::EntryPoint);
208        instruction.add_operand(execution_model as u32);
209        instruction.add_operand(entry_point_id);
210        instruction.add_operands(helpers::string_to_words(name));
211
212        for interface_id in interface_ids {
213            instruction.add_operand(*interface_id);
214        }
215
216        instruction
217    }
218
219    pub(super) fn execution_mode(
220        entry_point_id: Word,
221        execution_mode: spirv::ExecutionMode,
222        args: &[Word],
223    ) -> Self {
224        let mut instruction = Self::new(Op::ExecutionMode);
225        instruction.add_operand(entry_point_id);
226        instruction.add_operand(execution_mode as u32);
227        for arg in args {
228            instruction.add_operand(*arg);
229        }
230        instruction
231    }
232
233    pub(super) fn capability(capability: spirv::Capability) -> Self {
234        let mut instruction = Self::new(Op::Capability);
235        instruction.add_operand(capability as u32);
236        instruction
237    }
238
239    //
240    //  Type-Declaration Instructions
241    //
242
243    pub(super) fn type_void(id: Word) -> Self {
244        let mut instruction = Self::new(Op::TypeVoid);
245        instruction.set_result(id);
246        instruction
247    }
248
249    pub(super) fn type_bool(id: Word) -> Self {
250        let mut instruction = Self::new(Op::TypeBool);
251        instruction.set_result(id);
252        instruction
253    }
254
255    pub(super) fn type_int(id: Word, width: Word, signedness: Signedness) -> Self {
256        let mut instruction = Self::new(Op::TypeInt);
257        instruction.set_result(id);
258        instruction.add_operand(width);
259        instruction.add_operand(signedness as u32);
260        instruction
261    }
262
263    pub(super) fn type_float(id: Word, width: Word) -> Self {
264        let mut instruction = Self::new(Op::TypeFloat);
265        instruction.set_result(id);
266        instruction.add_operand(width);
267        instruction
268    }
269
270    pub(super) fn type_vector(
271        id: Word,
272        component_type_id: Word,
273        component_count: crate::VectorSize,
274    ) -> Self {
275        let mut instruction = Self::new(Op::TypeVector);
276        instruction.set_result(id);
277        instruction.add_operand(component_type_id);
278        instruction.add_operand(component_count as u32);
279        instruction
280    }
281
282    pub(super) fn type_matrix(
283        id: Word,
284        column_type_id: Word,
285        column_count: crate::VectorSize,
286    ) -> Self {
287        let mut instruction = Self::new(Op::TypeMatrix);
288        instruction.set_result(id);
289        instruction.add_operand(column_type_id);
290        instruction.add_operand(column_count as u32);
291        instruction
292    }
293
294    #[allow(clippy::too_many_arguments)]
295    pub(super) fn type_image(
296        id: Word,
297        sampled_type_id: Word,
298        dim: spirv::Dim,
299        flags: super::ImageTypeFlags,
300        image_format: spirv::ImageFormat,
301    ) -> Self {
302        let mut instruction = Self::new(Op::TypeImage);
303        instruction.set_result(id);
304        instruction.add_operand(sampled_type_id);
305        instruction.add_operand(dim as u32);
306        instruction.add_operand(flags.contains(super::ImageTypeFlags::DEPTH) as u32);
307        instruction.add_operand(flags.contains(super::ImageTypeFlags::ARRAYED) as u32);
308        instruction.add_operand(flags.contains(super::ImageTypeFlags::MULTISAMPLED) as u32);
309        instruction.add_operand(if flags.contains(super::ImageTypeFlags::SAMPLED) {
310            1
311        } else {
312            2
313        });
314        instruction.add_operand(image_format as u32);
315        instruction
316    }
317
318    pub(super) fn type_sampler(id: Word) -> Self {
319        let mut instruction = Self::new(Op::TypeSampler);
320        instruction.set_result(id);
321        instruction
322    }
323
324    pub(super) fn type_acceleration_structure(id: Word) -> Self {
325        let mut instruction = Self::new(Op::TypeAccelerationStructureKHR);
326        instruction.set_result(id);
327        instruction
328    }
329
330    pub(super) fn type_ray_query(id: Word) -> Self {
331        let mut instruction = Self::new(Op::TypeRayQueryKHR);
332        instruction.set_result(id);
333        instruction
334    }
335
336    pub(super) fn type_sampled_image(id: Word, image_type_id: Word) -> Self {
337        let mut instruction = Self::new(Op::TypeSampledImage);
338        instruction.set_result(id);
339        instruction.add_operand(image_type_id);
340        instruction
341    }
342
343    pub(super) fn type_array(id: Word, element_type_id: Word, length_id: Word) -> Self {
344        let mut instruction = Self::new(Op::TypeArray);
345        instruction.set_result(id);
346        instruction.add_operand(element_type_id);
347        instruction.add_operand(length_id);
348        instruction
349    }
350
351    pub(super) fn type_runtime_array(id: Word, element_type_id: Word) -> Self {
352        let mut instruction = Self::new(Op::TypeRuntimeArray);
353        instruction.set_result(id);
354        instruction.add_operand(element_type_id);
355        instruction
356    }
357
358    pub(super) fn type_struct(id: Word, member_ids: &[Word]) -> Self {
359        let mut instruction = Self::new(Op::TypeStruct);
360        instruction.set_result(id);
361
362        for member_id in member_ids {
363            instruction.add_operand(*member_id)
364        }
365
366        instruction
367    }
368
369    pub(super) fn type_pointer(
370        id: Word,
371        storage_class: spirv::StorageClass,
372        type_id: Word,
373    ) -> Self {
374        let mut instruction = Self::new(Op::TypePointer);
375        instruction.set_result(id);
376        instruction.add_operand(storage_class as u32);
377        instruction.add_operand(type_id);
378        instruction
379    }
380
381    pub(super) fn type_function(id: Word, return_type_id: Word, parameter_ids: &[Word]) -> Self {
382        let mut instruction = Self::new(Op::TypeFunction);
383        instruction.set_result(id);
384        instruction.add_operand(return_type_id);
385
386        for parameter_id in parameter_ids {
387            instruction.add_operand(*parameter_id);
388        }
389
390        instruction
391    }
392
393    //
394    //  Constant-Creation Instructions
395    //
396
397    pub(super) fn constant_null(result_type_id: Word, id: Word) -> Self {
398        let mut instruction = Self::new(Op::ConstantNull);
399        instruction.set_type(result_type_id);
400        instruction.set_result(id);
401        instruction
402    }
403
404    pub(super) fn constant_true(result_type_id: Word, id: Word) -> Self {
405        let mut instruction = Self::new(Op::ConstantTrue);
406        instruction.set_type(result_type_id);
407        instruction.set_result(id);
408        instruction
409    }
410
411    pub(super) fn constant_false(result_type_id: Word, id: Word) -> Self {
412        let mut instruction = Self::new(Op::ConstantFalse);
413        instruction.set_type(result_type_id);
414        instruction.set_result(id);
415        instruction
416    }
417
418    pub(super) fn constant_16bit(result_type_id: Word, id: Word, low: Word) -> Self {
419        Self::constant(result_type_id, id, &[low])
420    }
421
422    pub(super) fn constant_32bit(result_type_id: Word, id: Word, value: Word) -> Self {
423        Self::constant(result_type_id, id, &[value])
424    }
425
426    pub(super) fn constant_64bit(result_type_id: Word, id: Word, low: Word, high: Word) -> Self {
427        Self::constant(result_type_id, id, &[low, high])
428    }
429
430    pub(super) fn constant(result_type_id: Word, id: Word, values: &[Word]) -> Self {
431        let mut instruction = Self::new(Op::Constant);
432        instruction.set_type(result_type_id);
433        instruction.set_result(id);
434
435        for value in values {
436            instruction.add_operand(*value);
437        }
438
439        instruction
440    }
441
442    pub(super) fn constant_composite(
443        result_type_id: Word,
444        id: Word,
445        constituent_ids: &[Word],
446    ) -> Self {
447        let mut instruction = Self::new(Op::ConstantComposite);
448        instruction.set_type(result_type_id);
449        instruction.set_result(id);
450
451        for constituent_id in constituent_ids {
452            instruction.add_operand(*constituent_id);
453        }
454
455        instruction
456    }
457
458    //
459    //  Memory Instructions
460    //
461
462    pub(super) fn variable(
463        result_type_id: Word,
464        id: Word,
465        storage_class: spirv::StorageClass,
466        initializer_id: Option<Word>,
467    ) -> Self {
468        let mut instruction = Self::new(Op::Variable);
469        instruction.set_type(result_type_id);
470        instruction.set_result(id);
471        instruction.add_operand(storage_class as u32);
472
473        if let Some(initializer_id) = initializer_id {
474            instruction.add_operand(initializer_id);
475        }
476
477        instruction
478    }
479
480    pub(super) fn load(
481        result_type_id: Word,
482        id: Word,
483        pointer_id: Word,
484        memory_access: Option<spirv::MemoryAccess>,
485    ) -> Self {
486        let mut instruction = Self::new(Op::Load);
487        instruction.set_type(result_type_id);
488        instruction.set_result(id);
489        instruction.add_operand(pointer_id);
490
491        if let Some(memory_access) = memory_access {
492            instruction.add_operand(memory_access.bits());
493        }
494
495        instruction
496    }
497
498    pub(super) fn atomic_load(
499        result_type_id: Word,
500        id: Word,
501        pointer_id: Word,
502        scope_id: Word,
503        semantics_id: Word,
504    ) -> Self {
505        let mut instruction = Self::new(Op::AtomicLoad);
506        instruction.set_type(result_type_id);
507        instruction.set_result(id);
508        instruction.add_operand(pointer_id);
509        instruction.add_operand(scope_id);
510        instruction.add_operand(semantics_id);
511        instruction
512    }
513
514    pub(super) fn store(
515        pointer_id: Word,
516        value_id: Word,
517        memory_access: Option<spirv::MemoryAccess>,
518    ) -> Self {
519        let mut instruction = Self::new(Op::Store);
520        instruction.add_operand(pointer_id);
521        instruction.add_operand(value_id);
522
523        if let Some(memory_access) = memory_access {
524            instruction.add_operand(memory_access.bits());
525        }
526
527        instruction
528    }
529
530    pub(super) fn atomic_store(
531        pointer_id: Word,
532        scope_id: Word,
533        semantics_id: Word,
534        value_id: Word,
535    ) -> Self {
536        let mut instruction = Self::new(Op::AtomicStore);
537        instruction.add_operand(pointer_id);
538        instruction.add_operand(scope_id);
539        instruction.add_operand(semantics_id);
540        instruction.add_operand(value_id);
541        instruction
542    }
543
544    pub(super) fn access_chain(
545        result_type_id: Word,
546        id: Word,
547        base_id: Word,
548        index_ids: &[Word],
549    ) -> Self {
550        let mut instruction = Self::new(Op::AccessChain);
551        instruction.set_type(result_type_id);
552        instruction.set_result(id);
553        instruction.add_operand(base_id);
554
555        for index_id in index_ids {
556            instruction.add_operand(*index_id);
557        }
558
559        instruction
560    }
561
562    pub(super) fn array_length(
563        result_type_id: Word,
564        id: Word,
565        structure_id: Word,
566        array_member: Word,
567    ) -> Self {
568        let mut instruction = Self::new(Op::ArrayLength);
569        instruction.set_type(result_type_id);
570        instruction.set_result(id);
571        instruction.add_operand(structure_id);
572        instruction.add_operand(array_member);
573        instruction
574    }
575
576    //
577    //  Function Instructions
578    //
579
580    pub(super) fn function(
581        return_type_id: Word,
582        id: Word,
583        function_control: spirv::FunctionControl,
584        function_type_id: Word,
585    ) -> Self {
586        let mut instruction = Self::new(Op::Function);
587        instruction.set_type(return_type_id);
588        instruction.set_result(id);
589        instruction.add_operand(function_control.bits());
590        instruction.add_operand(function_type_id);
591        instruction
592    }
593
594    pub(super) fn function_parameter(result_type_id: Word, id: Word) -> Self {
595        let mut instruction = Self::new(Op::FunctionParameter);
596        instruction.set_type(result_type_id);
597        instruction.set_result(id);
598        instruction
599    }
600
601    pub(super) const fn function_end() -> Self {
602        Self::new(Op::FunctionEnd)
603    }
604
605    pub(super) fn function_call(
606        result_type_id: Word,
607        id: Word,
608        function_id: Word,
609        argument_ids: &[Word],
610    ) -> Self {
611        let mut instruction = Self::new(Op::FunctionCall);
612        instruction.set_type(result_type_id);
613        instruction.set_result(id);
614        instruction.add_operand(function_id);
615
616        for argument_id in argument_ids {
617            instruction.add_operand(*argument_id);
618        }
619
620        instruction
621    }
622
623    //
624    //  Image Instructions
625    //
626
627    pub(super) fn sampled_image(
628        result_type_id: Word,
629        id: Word,
630        image: Word,
631        sampler: Word,
632    ) -> Self {
633        let mut instruction = Self::new(Op::SampledImage);
634        instruction.set_type(result_type_id);
635        instruction.set_result(id);
636        instruction.add_operand(image);
637        instruction.add_operand(sampler);
638        instruction
639    }
640
641    pub(super) fn image_sample(
642        result_type_id: Word,
643        id: Word,
644        lod: SampleLod,
645        sampled_image: Word,
646        coordinates: Word,
647        depth_ref: Option<Word>,
648    ) -> Self {
649        let op = match (lod, depth_ref) {
650            (SampleLod::Explicit, None) => Op::ImageSampleExplicitLod,
651            (SampleLod::Implicit, None) => Op::ImageSampleImplicitLod,
652            (SampleLod::Explicit, Some(_)) => Op::ImageSampleDrefExplicitLod,
653            (SampleLod::Implicit, Some(_)) => Op::ImageSampleDrefImplicitLod,
654        };
655
656        let mut instruction = Self::new(op);
657        instruction.set_type(result_type_id);
658        instruction.set_result(id);
659        instruction.add_operand(sampled_image);
660        instruction.add_operand(coordinates);
661        if let Some(dref) = depth_ref {
662            instruction.add_operand(dref);
663        }
664
665        instruction
666    }
667
668    pub(super) fn image_gather(
669        result_type_id: Word,
670        id: Word,
671        sampled_image: Word,
672        coordinates: Word,
673        component_id: Word,
674        depth_ref: Option<Word>,
675    ) -> Self {
676        let op = match depth_ref {
677            None => Op::ImageGather,
678            Some(_) => Op::ImageDrefGather,
679        };
680
681        let mut instruction = Self::new(op);
682        instruction.set_type(result_type_id);
683        instruction.set_result(id);
684        instruction.add_operand(sampled_image);
685        instruction.add_operand(coordinates);
686        if let Some(dref) = depth_ref {
687            instruction.add_operand(dref);
688        } else {
689            instruction.add_operand(component_id);
690        }
691
692        instruction
693    }
694
695    pub(super) fn image_fetch_or_read(
696        op: Op,
697        result_type_id: Word,
698        id: Word,
699        image: Word,
700        coordinates: Word,
701    ) -> Self {
702        let mut instruction = Self::new(op);
703        instruction.set_type(result_type_id);
704        instruction.set_result(id);
705        instruction.add_operand(image);
706        instruction.add_operand(coordinates);
707        instruction
708    }
709
710    pub(super) fn image_write(image: Word, coordinates: Word, value: Word) -> Self {
711        let mut instruction = Self::new(Op::ImageWrite);
712        instruction.add_operand(image);
713        instruction.add_operand(coordinates);
714        instruction.add_operand(value);
715        instruction
716    }
717
718    pub(super) fn image_texel_pointer(
719        result_type_id: Word,
720        id: Word,
721        image: Word,
722        coordinates: Word,
723        sample: Word,
724    ) -> Self {
725        let mut instruction = Self::new(Op::ImageTexelPointer);
726        instruction.set_type(result_type_id);
727        instruction.set_result(id);
728        instruction.add_operand(image);
729        instruction.add_operand(coordinates);
730        instruction.add_operand(sample);
731        instruction
732    }
733
734    pub(super) fn image_atomic(
735        op: Op,
736        result_type_id: Word,
737        id: Word,
738        pointer: Word,
739        scope_id: Word,
740        semantics_id: Word,
741        value: Word,
742    ) -> Self {
743        let mut instruction = Self::new(op);
744        instruction.set_type(result_type_id);
745        instruction.set_result(id);
746        instruction.add_operand(pointer);
747        instruction.add_operand(scope_id);
748        instruction.add_operand(semantics_id);
749        instruction.add_operand(value);
750        instruction
751    }
752
753    pub(super) fn image_query(op: Op, result_type_id: Word, id: Word, image: Word) -> Self {
754        let mut instruction = Self::new(op);
755        instruction.set_type(result_type_id);
756        instruction.set_result(id);
757        instruction.add_operand(image);
758        instruction
759    }
760
761    //
762    //  Ray Query Instructions
763    //
764    #[allow(clippy::too_many_arguments)]
765    pub(super) fn ray_query_initialize(
766        query: Word,
767        acceleration_structure: Word,
768        ray_flags: Word,
769        cull_mask: Word,
770        ray_origin: Word,
771        ray_tmin: Word,
772        ray_dir: Word,
773        ray_tmax: Word,
774    ) -> Self {
775        let mut instruction = Self::new(Op::RayQueryInitializeKHR);
776        instruction.add_operand(query);
777        instruction.add_operand(acceleration_structure);
778        instruction.add_operand(ray_flags);
779        instruction.add_operand(cull_mask);
780        instruction.add_operand(ray_origin);
781        instruction.add_operand(ray_tmin);
782        instruction.add_operand(ray_dir);
783        instruction.add_operand(ray_tmax);
784        instruction
785    }
786
787    pub(super) fn ray_query_proceed(result_type_id: Word, id: Word, query: Word) -> Self {
788        let mut instruction = Self::new(Op::RayQueryProceedKHR);
789        instruction.set_type(result_type_id);
790        instruction.set_result(id);
791        instruction.add_operand(query);
792        instruction
793    }
794
795    pub(super) fn ray_query_generate_intersection(query: Word, hit: Word) -> Self {
796        let mut instruction = Self::new(Op::RayQueryGenerateIntersectionKHR);
797        instruction.add_operand(query);
798        instruction.add_operand(hit);
799        instruction
800    }
801
802    pub(super) fn ray_query_confirm_intersection(query: Word) -> Self {
803        let mut instruction = Self::new(Op::RayQueryConfirmIntersectionKHR);
804        instruction.add_operand(query);
805        instruction
806    }
807
808    pub(super) fn ray_query_return_vertex_position(
809        result_type_id: Word,
810        id: Word,
811        query: Word,
812        intersection: Word,
813    ) -> Self {
814        let mut instruction = Self::new(Op::RayQueryGetIntersectionTriangleVertexPositionsKHR);
815        instruction.set_type(result_type_id);
816        instruction.set_result(id);
817        instruction.add_operand(query);
818        instruction.add_operand(intersection);
819        instruction
820    }
821
822    pub(super) fn ray_query_get_intersection(
823        op: Op,
824        result_type_id: Word,
825        id: Word,
826        query: Word,
827        intersection: Word,
828    ) -> Self {
829        let mut instruction = Self::new(op);
830        instruction.set_type(result_type_id);
831        instruction.set_result(id);
832        instruction.add_operand(query);
833        instruction.add_operand(intersection);
834        instruction
835    }
836
837    pub(super) fn ray_query_get_t_min(result_type_id: Word, id: Word, query: Word) -> Self {
838        let mut instruction = Self::new(Op::RayQueryGetRayTMinKHR);
839        instruction.set_type(result_type_id);
840        instruction.set_result(id);
841        instruction.add_operand(query);
842        instruction
843    }
844
845    //
846    //  Conversion Instructions
847    //
848    pub(super) fn unary(op: Op, result_type_id: Word, id: Word, value: Word) -> Self {
849        let mut instruction = Self::new(op);
850        instruction.set_type(result_type_id);
851        instruction.set_result(id);
852        instruction.add_operand(value);
853        instruction
854    }
855
856    //
857    //  Composite Instructions
858    //
859
860    pub(super) fn composite_construct(
861        result_type_id: Word,
862        id: Word,
863        constituent_ids: &[Word],
864    ) -> Self {
865        let mut instruction = Self::new(Op::CompositeConstruct);
866        instruction.set_type(result_type_id);
867        instruction.set_result(id);
868
869        for constituent_id in constituent_ids {
870            instruction.add_operand(*constituent_id);
871        }
872
873        instruction
874    }
875
876    pub(super) fn composite_extract(
877        result_type_id: Word,
878        id: Word,
879        composite_id: Word,
880        indices: &[Word],
881    ) -> Self {
882        let mut instruction = Self::new(Op::CompositeExtract);
883        instruction.set_type(result_type_id);
884        instruction.set_result(id);
885
886        instruction.add_operand(composite_id);
887        for index in indices {
888            instruction.add_operand(*index);
889        }
890
891        instruction
892    }
893
894    pub(super) fn vector_extract_dynamic(
895        result_type_id: Word,
896        id: Word,
897        vector_id: Word,
898        index_id: Word,
899    ) -> Self {
900        let mut instruction = Self::new(Op::VectorExtractDynamic);
901        instruction.set_type(result_type_id);
902        instruction.set_result(id);
903
904        instruction.add_operand(vector_id);
905        instruction.add_operand(index_id);
906
907        instruction
908    }
909
910    pub(super) fn vector_shuffle(
911        result_type_id: Word,
912        id: Word,
913        v1_id: Word,
914        v2_id: Word,
915        components: &[Word],
916    ) -> Self {
917        let mut instruction = Self::new(Op::VectorShuffle);
918        instruction.set_type(result_type_id);
919        instruction.set_result(id);
920        instruction.add_operand(v1_id);
921        instruction.add_operand(v2_id);
922
923        for &component in components {
924            instruction.add_operand(component);
925        }
926
927        instruction
928    }
929
930    //
931    // Arithmetic Instructions
932    //
933    pub(super) fn binary(
934        op: Op,
935        result_type_id: Word,
936        id: Word,
937        operand_1: Word,
938        operand_2: Word,
939    ) -> Self {
940        let mut instruction = Self::new(op);
941        instruction.set_type(result_type_id);
942        instruction.set_result(id);
943        instruction.add_operand(operand_1);
944        instruction.add_operand(operand_2);
945        instruction
946    }
947
948    pub(super) fn ternary(
949        op: Op,
950        result_type_id: Word,
951        id: Word,
952        operand_1: Word,
953        operand_2: Word,
954        operand_3: Word,
955    ) -> Self {
956        let mut instruction = Self::new(op);
957        instruction.set_type(result_type_id);
958        instruction.set_result(id);
959        instruction.add_operand(operand_1);
960        instruction.add_operand(operand_2);
961        instruction.add_operand(operand_3);
962        instruction
963    }
964
965    pub(super) fn quaternary(
966        op: Op,
967        result_type_id: Word,
968        id: Word,
969        operand_1: Word,
970        operand_2: Word,
971        operand_3: Word,
972        operand_4: Word,
973    ) -> Self {
974        let mut instruction = Self::new(op);
975        instruction.set_type(result_type_id);
976        instruction.set_result(id);
977        instruction.add_operand(operand_1);
978        instruction.add_operand(operand_2);
979        instruction.add_operand(operand_3);
980        instruction.add_operand(operand_4);
981        instruction
982    }
983
984    pub(super) fn relational(op: Op, result_type_id: Word, id: Word, expr_id: Word) -> Self {
985        let mut instruction = Self::new(op);
986        instruction.set_type(result_type_id);
987        instruction.set_result(id);
988        instruction.add_operand(expr_id);
989        instruction
990    }
991
992    pub(super) fn atomic_binary(
993        op: Op,
994        result_type_id: Word,
995        id: Word,
996        pointer: Word,
997        scope_id: Word,
998        semantics_id: Word,
999        value: Word,
1000    ) -> Self {
1001        let mut instruction = Self::new(op);
1002        instruction.set_type(result_type_id);
1003        instruction.set_result(id);
1004        instruction.add_operand(pointer);
1005        instruction.add_operand(scope_id);
1006        instruction.add_operand(semantics_id);
1007        instruction.add_operand(value);
1008        instruction
1009    }
1010
1011    //
1012    // Bit Instructions
1013    //
1014
1015    //
1016    // Relational and Logical Instructions
1017    //
1018
1019    //
1020    // Derivative Instructions
1021    //
1022
1023    pub(super) fn derivative(op: Op, result_type_id: Word, id: Word, expr_id: Word) -> Self {
1024        let mut instruction = Self::new(op);
1025        instruction.set_type(result_type_id);
1026        instruction.set_result(id);
1027        instruction.add_operand(expr_id);
1028        instruction
1029    }
1030
1031    //
1032    // Control-Flow Instructions
1033    //
1034
1035    pub(super) fn phi(
1036        result_type_id: Word,
1037        result_id: Word,
1038        var_parent_pairs: &[(Word, Word)],
1039    ) -> Self {
1040        let mut instruction = Self::new(Op::Phi);
1041        instruction.add_operand(result_type_id);
1042        instruction.add_operand(result_id);
1043        for &(variable, parent) in var_parent_pairs {
1044            instruction.add_operand(variable);
1045            instruction.add_operand(parent);
1046        }
1047        instruction
1048    }
1049
1050    pub(super) fn selection_merge(
1051        merge_id: Word,
1052        selection_control: spirv::SelectionControl,
1053    ) -> Self {
1054        let mut instruction = Self::new(Op::SelectionMerge);
1055        instruction.add_operand(merge_id);
1056        instruction.add_operand(selection_control.bits());
1057        instruction
1058    }
1059
1060    pub(super) fn loop_merge(
1061        merge_id: Word,
1062        continuing_id: Word,
1063        selection_control: spirv::SelectionControl,
1064    ) -> Self {
1065        let mut instruction = Self::new(Op::LoopMerge);
1066        instruction.add_operand(merge_id);
1067        instruction.add_operand(continuing_id);
1068        instruction.add_operand(selection_control.bits());
1069        instruction
1070    }
1071
1072    pub(super) fn label(id: Word) -> Self {
1073        let mut instruction = Self::new(Op::Label);
1074        instruction.set_result(id);
1075        instruction
1076    }
1077
1078    pub(super) fn branch(id: Word) -> Self {
1079        let mut instruction = Self::new(Op::Branch);
1080        instruction.add_operand(id);
1081        instruction
1082    }
1083
1084    // TODO Branch Weights not implemented.
1085    pub(super) fn branch_conditional(
1086        condition_id: Word,
1087        true_label: Word,
1088        false_label: Word,
1089    ) -> Self {
1090        let mut instruction = Self::new(Op::BranchConditional);
1091        instruction.add_operand(condition_id);
1092        instruction.add_operand(true_label);
1093        instruction.add_operand(false_label);
1094        instruction
1095    }
1096
1097    pub(super) fn switch(selector_id: Word, default_id: Word, cases: &[Case]) -> Self {
1098        let mut instruction = Self::new(Op::Switch);
1099        instruction.add_operand(selector_id);
1100        instruction.add_operand(default_id);
1101        for case in cases {
1102            instruction.add_operand(case.value);
1103            instruction.add_operand(case.label_id);
1104        }
1105        instruction
1106    }
1107
1108    pub(super) fn select(
1109        result_type_id: Word,
1110        id: Word,
1111        condition_id: Word,
1112        accept_id: Word,
1113        reject_id: Word,
1114    ) -> Self {
1115        let mut instruction = Self::new(Op::Select);
1116        instruction.add_operand(result_type_id);
1117        instruction.add_operand(id);
1118        instruction.add_operand(condition_id);
1119        instruction.add_operand(accept_id);
1120        instruction.add_operand(reject_id);
1121        instruction
1122    }
1123
1124    pub(super) const fn kill() -> Self {
1125        Self::new(Op::Kill)
1126    }
1127
1128    pub(super) const fn return_void() -> Self {
1129        Self::new(Op::Return)
1130    }
1131
1132    pub(super) fn return_value(value_id: Word) -> Self {
1133        let mut instruction = Self::new(Op::ReturnValue);
1134        instruction.add_operand(value_id);
1135        instruction
1136    }
1137
1138    //
1139    //  Atomic Instructions
1140    //
1141
1142    //
1143    //  Primitive Instructions
1144    //
1145
1146    // Barriers
1147
1148    pub(super) fn control_barrier(
1149        exec_scope_id: Word,
1150        mem_scope_id: Word,
1151        semantics_id: Word,
1152    ) -> Self {
1153        let mut instruction = Self::new(Op::ControlBarrier);
1154        instruction.add_operand(exec_scope_id);
1155        instruction.add_operand(mem_scope_id);
1156        instruction.add_operand(semantics_id);
1157        instruction
1158    }
1159    pub(super) fn memory_barrier(mem_scope_id: Word, semantics_id: Word) -> Self {
1160        let mut instruction = Self::new(Op::MemoryBarrier);
1161        instruction.add_operand(mem_scope_id);
1162        instruction.add_operand(semantics_id);
1163        instruction
1164    }
1165
1166    // Group Instructions
1167
1168    pub(super) fn group_non_uniform_ballot(
1169        result_type_id: Word,
1170        id: Word,
1171        exec_scope_id: Word,
1172        predicate: Word,
1173    ) -> Self {
1174        let mut instruction = Self::new(Op::GroupNonUniformBallot);
1175        instruction.set_type(result_type_id);
1176        instruction.set_result(id);
1177        instruction.add_operand(exec_scope_id);
1178        instruction.add_operand(predicate);
1179
1180        instruction
1181    }
1182    pub(super) fn group_non_uniform_broadcast_first(
1183        result_type_id: Word,
1184        id: Word,
1185        exec_scope_id: Word,
1186        value: Word,
1187    ) -> Self {
1188        let mut instruction = Self::new(Op::GroupNonUniformBroadcastFirst);
1189        instruction.set_type(result_type_id);
1190        instruction.set_result(id);
1191        instruction.add_operand(exec_scope_id);
1192        instruction.add_operand(value);
1193
1194        instruction
1195    }
1196    pub(super) fn group_non_uniform_gather(
1197        op: Op,
1198        result_type_id: Word,
1199        id: Word,
1200        exec_scope_id: Word,
1201        value: Word,
1202        index: Word,
1203    ) -> Self {
1204        let mut instruction = Self::new(op);
1205        instruction.set_type(result_type_id);
1206        instruction.set_result(id);
1207        instruction.add_operand(exec_scope_id);
1208        instruction.add_operand(value);
1209        instruction.add_operand(index);
1210
1211        instruction
1212    }
1213    pub(super) fn group_non_uniform_arithmetic(
1214        op: Op,
1215        result_type_id: Word,
1216        id: Word,
1217        exec_scope_id: Word,
1218        group_op: Option<spirv::GroupOperation>,
1219        value: Word,
1220    ) -> Self {
1221        let mut instruction = Self::new(op);
1222        instruction.set_type(result_type_id);
1223        instruction.set_result(id);
1224        instruction.add_operand(exec_scope_id);
1225        if let Some(group_op) = group_op {
1226            instruction.add_operand(group_op as u32);
1227        }
1228        instruction.add_operand(value);
1229
1230        instruction
1231    }
1232    pub(super) fn group_non_uniform_quad_swap(
1233        result_type_id: Word,
1234        id: Word,
1235        exec_scope_id: Word,
1236        value: Word,
1237        direction: Word,
1238    ) -> Self {
1239        let mut instruction = Self::new(Op::GroupNonUniformQuadSwap);
1240        instruction.set_type(result_type_id);
1241        instruction.set_result(id);
1242        instruction.add_operand(exec_scope_id);
1243        instruction.add_operand(value);
1244        instruction.add_operand(direction);
1245
1246        instruction
1247    }
1248}
1249
1250impl From<crate::StorageFormat> for spirv::ImageFormat {
1251    fn from(format: crate::StorageFormat) -> Self {
1252        use crate::StorageFormat as Sf;
1253        match format {
1254            Sf::R8Unorm => Self::R8,
1255            Sf::R8Snorm => Self::R8Snorm,
1256            Sf::R8Uint => Self::R8ui,
1257            Sf::R8Sint => Self::R8i,
1258            Sf::R16Uint => Self::R16ui,
1259            Sf::R16Sint => Self::R16i,
1260            Sf::R16Float => Self::R16f,
1261            Sf::Rg8Unorm => Self::Rg8,
1262            Sf::Rg8Snorm => Self::Rg8Snorm,
1263            Sf::Rg8Uint => Self::Rg8ui,
1264            Sf::Rg8Sint => Self::Rg8i,
1265            Sf::R32Uint => Self::R32ui,
1266            Sf::R32Sint => Self::R32i,
1267            Sf::R32Float => Self::R32f,
1268            Sf::Rg16Uint => Self::Rg16ui,
1269            Sf::Rg16Sint => Self::Rg16i,
1270            Sf::Rg16Float => Self::Rg16f,
1271            Sf::Rgba8Unorm => Self::Rgba8,
1272            Sf::Rgba8Snorm => Self::Rgba8Snorm,
1273            Sf::Rgba8Uint => Self::Rgba8ui,
1274            Sf::Rgba8Sint => Self::Rgba8i,
1275            Sf::Bgra8Unorm => Self::Unknown,
1276            Sf::Rgb10a2Uint => Self::Rgb10a2ui,
1277            Sf::Rgb10a2Unorm => Self::Rgb10A2,
1278            Sf::Rg11b10Ufloat => Self::R11fG11fB10f,
1279            Sf::R64Uint => Self::R64ui,
1280            Sf::Rg32Uint => Self::Rg32ui,
1281            Sf::Rg32Sint => Self::Rg32i,
1282            Sf::Rg32Float => Self::Rg32f,
1283            Sf::Rgba16Uint => Self::Rgba16ui,
1284            Sf::Rgba16Sint => Self::Rgba16i,
1285            Sf::Rgba16Float => Self::Rgba16f,
1286            Sf::Rgba32Uint => Self::Rgba32ui,
1287            Sf::Rgba32Sint => Self::Rgba32i,
1288            Sf::Rgba32Float => Self::Rgba32f,
1289            Sf::R16Unorm => Self::R16,
1290            Sf::R16Snorm => Self::R16Snorm,
1291            Sf::Rg16Unorm => Self::Rg16,
1292            Sf::Rg16Snorm => Self::Rg16Snorm,
1293            Sf::Rgba16Unorm => Self::Rgba16,
1294            Sf::Rgba16Snorm => Self::Rgba16Snorm,
1295        }
1296    }
1297}
1298
1299impl From<crate::ImageDimension> for spirv::Dim {
1300    fn from(dim: crate::ImageDimension) -> Self {
1301        use crate::ImageDimension as Id;
1302        match dim {
1303            Id::D1 => Self::Dim1D,
1304            Id::D2 => Self::Dim2D,
1305            Id::D3 => Self::Dim3D,
1306            Id::Cube => Self::DimCube,
1307        }
1308    }
1309}