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    pub(super) fn type_coop_matrix(
295        id: Word,
296        scalar_type_id: Word,
297        scope_id: Word,
298        row_count_id: Word,
299        column_count_id: Word,
300        matrix_use_id: Word,
301    ) -> Self {
302        let mut instruction = Self::new(Op::TypeCooperativeMatrixKHR);
303        instruction.set_result(id);
304        instruction.add_operand(scalar_type_id);
305        instruction.add_operand(scope_id);
306        instruction.add_operand(row_count_id);
307        instruction.add_operand(column_count_id);
308        instruction.add_operand(matrix_use_id);
309        instruction
310    }
311
312    #[allow(clippy::too_many_arguments)]
313    pub(super) fn type_image(
314        id: Word,
315        sampled_type_id: Word,
316        dim: spirv::Dim,
317        flags: super::ImageTypeFlags,
318        image_format: spirv::ImageFormat,
319    ) -> Self {
320        let mut instruction = Self::new(Op::TypeImage);
321        instruction.set_result(id);
322        instruction.add_operand(sampled_type_id);
323        instruction.add_operand(dim as u32);
324        instruction.add_operand(flags.contains(super::ImageTypeFlags::DEPTH) as u32);
325        instruction.add_operand(flags.contains(super::ImageTypeFlags::ARRAYED) as u32);
326        instruction.add_operand(flags.contains(super::ImageTypeFlags::MULTISAMPLED) as u32);
327        instruction.add_operand(if flags.contains(super::ImageTypeFlags::SAMPLED) {
328            1
329        } else {
330            2
331        });
332        instruction.add_operand(image_format as u32);
333        instruction
334    }
335
336    pub(super) fn type_sampler(id: Word) -> Self {
337        let mut instruction = Self::new(Op::TypeSampler);
338        instruction.set_result(id);
339        instruction
340    }
341
342    pub(super) fn type_acceleration_structure(id: Word) -> Self {
343        let mut instruction = Self::new(Op::TypeAccelerationStructureKHR);
344        instruction.set_result(id);
345        instruction
346    }
347
348    pub(super) fn type_ray_query(id: Word) -> Self {
349        let mut instruction = Self::new(Op::TypeRayQueryKHR);
350        instruction.set_result(id);
351        instruction
352    }
353
354    pub(super) fn type_sampled_image(id: Word, image_type_id: Word) -> Self {
355        let mut instruction = Self::new(Op::TypeSampledImage);
356        instruction.set_result(id);
357        instruction.add_operand(image_type_id);
358        instruction
359    }
360
361    pub(super) fn type_array(id: Word, element_type_id: Word, length_id: Word) -> Self {
362        let mut instruction = Self::new(Op::TypeArray);
363        instruction.set_result(id);
364        instruction.add_operand(element_type_id);
365        instruction.add_operand(length_id);
366        instruction
367    }
368
369    pub(super) fn type_runtime_array(id: Word, element_type_id: Word) -> Self {
370        let mut instruction = Self::new(Op::TypeRuntimeArray);
371        instruction.set_result(id);
372        instruction.add_operand(element_type_id);
373        instruction
374    }
375
376    pub(super) fn type_struct(id: Word, member_ids: &[Word]) -> Self {
377        let mut instruction = Self::new(Op::TypeStruct);
378        instruction.set_result(id);
379
380        for member_id in member_ids {
381            instruction.add_operand(*member_id)
382        }
383
384        instruction
385    }
386
387    pub(super) fn type_pointer(
388        id: Word,
389        storage_class: spirv::StorageClass,
390        type_id: Word,
391    ) -> Self {
392        let mut instruction = Self::new(Op::TypePointer);
393        instruction.set_result(id);
394        instruction.add_operand(storage_class as u32);
395        instruction.add_operand(type_id);
396        instruction
397    }
398
399    pub(super) fn type_function(id: Word, return_type_id: Word, parameter_ids: &[Word]) -> Self {
400        let mut instruction = Self::new(Op::TypeFunction);
401        instruction.set_result(id);
402        instruction.add_operand(return_type_id);
403
404        for parameter_id in parameter_ids {
405            instruction.add_operand(*parameter_id);
406        }
407
408        instruction
409    }
410
411    //
412    //  Constant-Creation Instructions
413    //
414
415    pub(super) fn constant_null(result_type_id: Word, id: Word) -> Self {
416        let mut instruction = Self::new(Op::ConstantNull);
417        instruction.set_type(result_type_id);
418        instruction.set_result(id);
419        instruction
420    }
421
422    pub(super) fn constant_true(result_type_id: Word, id: Word) -> Self {
423        let mut instruction = Self::new(Op::ConstantTrue);
424        instruction.set_type(result_type_id);
425        instruction.set_result(id);
426        instruction
427    }
428
429    pub(super) fn constant_false(result_type_id: Word, id: Word) -> Self {
430        let mut instruction = Self::new(Op::ConstantFalse);
431        instruction.set_type(result_type_id);
432        instruction.set_result(id);
433        instruction
434    }
435
436    pub(super) fn constant_16bit(result_type_id: Word, id: Word, low: Word) -> Self {
437        Self::constant(result_type_id, id, &[low])
438    }
439
440    pub(super) fn constant_32bit(result_type_id: Word, id: Word, value: Word) -> Self {
441        Self::constant(result_type_id, id, &[value])
442    }
443
444    pub(super) fn constant_64bit(result_type_id: Word, id: Word, low: Word, high: Word) -> Self {
445        Self::constant(result_type_id, id, &[low, high])
446    }
447
448    pub(super) fn constant(result_type_id: Word, id: Word, values: &[Word]) -> Self {
449        let mut instruction = Self::new(Op::Constant);
450        instruction.set_type(result_type_id);
451        instruction.set_result(id);
452
453        for value in values {
454            instruction.add_operand(*value);
455        }
456
457        instruction
458    }
459
460    pub(super) fn constant_composite(
461        result_type_id: Word,
462        id: Word,
463        constituent_ids: &[Word],
464    ) -> Self {
465        let mut instruction = Self::new(Op::ConstantComposite);
466        instruction.set_type(result_type_id);
467        instruction.set_result(id);
468
469        for constituent_id in constituent_ids {
470            instruction.add_operand(*constituent_id);
471        }
472
473        instruction
474    }
475
476    //
477    //  Memory Instructions
478    //
479
480    pub(super) fn variable(
481        result_type_id: Word,
482        id: Word,
483        storage_class: spirv::StorageClass,
484        initializer_id: Option<Word>,
485    ) -> Self {
486        let mut instruction = Self::new(Op::Variable);
487        instruction.set_type(result_type_id);
488        instruction.set_result(id);
489        instruction.add_operand(storage_class as u32);
490
491        if let Some(initializer_id) = initializer_id {
492            instruction.add_operand(initializer_id);
493        }
494
495        instruction
496    }
497
498    pub(super) fn load(
499        result_type_id: Word,
500        id: Word,
501        pointer_id: Word,
502        memory_access: Option<spirv::MemoryAccess>,
503    ) -> Self {
504        let mut instruction = Self::new(Op::Load);
505        instruction.set_type(result_type_id);
506        instruction.set_result(id);
507        instruction.add_operand(pointer_id);
508
509        if let Some(memory_access) = memory_access {
510            instruction.add_operand(memory_access.bits());
511        }
512
513        instruction
514    }
515
516    pub(super) fn atomic_load(
517        result_type_id: Word,
518        id: Word,
519        pointer_id: Word,
520        scope_id: Word,
521        semantics_id: Word,
522    ) -> Self {
523        let mut instruction = Self::new(Op::AtomicLoad);
524        instruction.set_type(result_type_id);
525        instruction.set_result(id);
526        instruction.add_operand(pointer_id);
527        instruction.add_operand(scope_id);
528        instruction.add_operand(semantics_id);
529        instruction
530    }
531
532    pub(super) fn store(
533        pointer_id: Word,
534        value_id: Word,
535        memory_access: Option<spirv::MemoryAccess>,
536    ) -> Self {
537        let mut instruction = Self::new(Op::Store);
538        instruction.add_operand(pointer_id);
539        instruction.add_operand(value_id);
540
541        if let Some(memory_access) = memory_access {
542            instruction.add_operand(memory_access.bits());
543        }
544
545        instruction
546    }
547
548    pub(super) fn atomic_store(
549        pointer_id: Word,
550        scope_id: Word,
551        semantics_id: Word,
552        value_id: Word,
553    ) -> Self {
554        let mut instruction = Self::new(Op::AtomicStore);
555        instruction.add_operand(pointer_id);
556        instruction.add_operand(scope_id);
557        instruction.add_operand(semantics_id);
558        instruction.add_operand(value_id);
559        instruction
560    }
561
562    pub(super) fn access_chain(
563        result_type_id: Word,
564        id: Word,
565        base_id: Word,
566        index_ids: &[Word],
567    ) -> Self {
568        let mut instruction = Self::new(Op::AccessChain);
569        instruction.set_type(result_type_id);
570        instruction.set_result(id);
571        instruction.add_operand(base_id);
572
573        for index_id in index_ids {
574            instruction.add_operand(*index_id);
575        }
576
577        instruction
578    }
579
580    pub(super) fn array_length(
581        result_type_id: Word,
582        id: Word,
583        structure_id: Word,
584        array_member: Word,
585    ) -> Self {
586        let mut instruction = Self::new(Op::ArrayLength);
587        instruction.set_type(result_type_id);
588        instruction.set_result(id);
589        instruction.add_operand(structure_id);
590        instruction.add_operand(array_member);
591        instruction
592    }
593
594    //
595    //  Function Instructions
596    //
597
598    pub(super) fn function(
599        return_type_id: Word,
600        id: Word,
601        function_control: spirv::FunctionControl,
602        function_type_id: Word,
603    ) -> Self {
604        let mut instruction = Self::new(Op::Function);
605        instruction.set_type(return_type_id);
606        instruction.set_result(id);
607        instruction.add_operand(function_control.bits());
608        instruction.add_operand(function_type_id);
609        instruction
610    }
611
612    pub(super) fn function_parameter(result_type_id: Word, id: Word) -> Self {
613        let mut instruction = Self::new(Op::FunctionParameter);
614        instruction.set_type(result_type_id);
615        instruction.set_result(id);
616        instruction
617    }
618
619    pub(super) const fn function_end() -> Self {
620        Self::new(Op::FunctionEnd)
621    }
622
623    pub(super) fn function_call(
624        result_type_id: Word,
625        id: Word,
626        function_id: Word,
627        argument_ids: &[Word],
628    ) -> Self {
629        let mut instruction = Self::new(Op::FunctionCall);
630        instruction.set_type(result_type_id);
631        instruction.set_result(id);
632        instruction.add_operand(function_id);
633
634        for argument_id in argument_ids {
635            instruction.add_operand(*argument_id);
636        }
637
638        instruction
639    }
640
641    //
642    //  Image Instructions
643    //
644
645    pub(super) fn sampled_image(
646        result_type_id: Word,
647        id: Word,
648        image: Word,
649        sampler: Word,
650    ) -> Self {
651        let mut instruction = Self::new(Op::SampledImage);
652        instruction.set_type(result_type_id);
653        instruction.set_result(id);
654        instruction.add_operand(image);
655        instruction.add_operand(sampler);
656        instruction
657    }
658
659    pub(super) fn image_sample(
660        result_type_id: Word,
661        id: Word,
662        lod: SampleLod,
663        sampled_image: Word,
664        coordinates: Word,
665        depth_ref: Option<Word>,
666    ) -> Self {
667        let op = match (lod, depth_ref) {
668            (SampleLod::Explicit, None) => Op::ImageSampleExplicitLod,
669            (SampleLod::Implicit, None) => Op::ImageSampleImplicitLod,
670            (SampleLod::Explicit, Some(_)) => Op::ImageSampleDrefExplicitLod,
671            (SampleLod::Implicit, Some(_)) => Op::ImageSampleDrefImplicitLod,
672        };
673
674        let mut instruction = Self::new(op);
675        instruction.set_type(result_type_id);
676        instruction.set_result(id);
677        instruction.add_operand(sampled_image);
678        instruction.add_operand(coordinates);
679        if let Some(dref) = depth_ref {
680            instruction.add_operand(dref);
681        }
682
683        instruction
684    }
685
686    pub(super) fn image_gather(
687        result_type_id: Word,
688        id: Word,
689        sampled_image: Word,
690        coordinates: Word,
691        component_id: Word,
692        depth_ref: Option<Word>,
693    ) -> Self {
694        let op = match depth_ref {
695            None => Op::ImageGather,
696            Some(_) => Op::ImageDrefGather,
697        };
698
699        let mut instruction = Self::new(op);
700        instruction.set_type(result_type_id);
701        instruction.set_result(id);
702        instruction.add_operand(sampled_image);
703        instruction.add_operand(coordinates);
704        if let Some(dref) = depth_ref {
705            instruction.add_operand(dref);
706        } else {
707            instruction.add_operand(component_id);
708        }
709
710        instruction
711    }
712
713    pub(super) fn image_fetch_or_read(
714        op: Op,
715        result_type_id: Word,
716        id: Word,
717        image: Word,
718        coordinates: Word,
719    ) -> Self {
720        let mut instruction = Self::new(op);
721        instruction.set_type(result_type_id);
722        instruction.set_result(id);
723        instruction.add_operand(image);
724        instruction.add_operand(coordinates);
725        instruction
726    }
727
728    pub(super) fn image_write(image: Word, coordinates: Word, value: Word) -> Self {
729        let mut instruction = Self::new(Op::ImageWrite);
730        instruction.add_operand(image);
731        instruction.add_operand(coordinates);
732        instruction.add_operand(value);
733        instruction
734    }
735
736    pub(super) fn image_texel_pointer(
737        result_type_id: Word,
738        id: Word,
739        image: Word,
740        coordinates: Word,
741        sample: Word,
742    ) -> Self {
743        let mut instruction = Self::new(Op::ImageTexelPointer);
744        instruction.set_type(result_type_id);
745        instruction.set_result(id);
746        instruction.add_operand(image);
747        instruction.add_operand(coordinates);
748        instruction.add_operand(sample);
749        instruction
750    }
751
752    pub(super) fn image_atomic(
753        op: Op,
754        result_type_id: Word,
755        id: Word,
756        pointer: Word,
757        scope_id: Word,
758        semantics_id: Word,
759        value: Word,
760    ) -> Self {
761        let mut instruction = Self::new(op);
762        instruction.set_type(result_type_id);
763        instruction.set_result(id);
764        instruction.add_operand(pointer);
765        instruction.add_operand(scope_id);
766        instruction.add_operand(semantics_id);
767        instruction.add_operand(value);
768        instruction
769    }
770
771    pub(super) fn image_query(op: Op, result_type_id: Word, id: Word, image: Word) -> Self {
772        let mut instruction = Self::new(op);
773        instruction.set_type(result_type_id);
774        instruction.set_result(id);
775        instruction.add_operand(image);
776        instruction
777    }
778
779    //
780    //  Ray Query Instructions
781    //
782    #[allow(clippy::too_many_arguments)]
783    pub(super) fn ray_query_initialize(
784        query: Word,
785        acceleration_structure: Word,
786        ray_flags: Word,
787        cull_mask: Word,
788        ray_origin: Word,
789        ray_tmin: Word,
790        ray_dir: Word,
791        ray_tmax: Word,
792    ) -> Self {
793        let mut instruction = Self::new(Op::RayQueryInitializeKHR);
794        instruction.add_operand(query);
795        instruction.add_operand(acceleration_structure);
796        instruction.add_operand(ray_flags);
797        instruction.add_operand(cull_mask);
798        instruction.add_operand(ray_origin);
799        instruction.add_operand(ray_tmin);
800        instruction.add_operand(ray_dir);
801        instruction.add_operand(ray_tmax);
802        instruction
803    }
804
805    pub(super) fn ray_query_proceed(result_type_id: Word, id: Word, query: Word) -> Self {
806        let mut instruction = Self::new(Op::RayQueryProceedKHR);
807        instruction.set_type(result_type_id);
808        instruction.set_result(id);
809        instruction.add_operand(query);
810        instruction
811    }
812
813    pub(super) fn ray_query_generate_intersection(query: Word, hit: Word) -> Self {
814        let mut instruction = Self::new(Op::RayQueryGenerateIntersectionKHR);
815        instruction.add_operand(query);
816        instruction.add_operand(hit);
817        instruction
818    }
819
820    pub(super) fn ray_query_confirm_intersection(query: Word) -> Self {
821        let mut instruction = Self::new(Op::RayQueryConfirmIntersectionKHR);
822        instruction.add_operand(query);
823        instruction
824    }
825
826    pub(super) fn ray_query_return_vertex_position(
827        result_type_id: Word,
828        id: Word,
829        query: Word,
830        intersection: Word,
831    ) -> Self {
832        let mut instruction = Self::new(Op::RayQueryGetIntersectionTriangleVertexPositionsKHR);
833        instruction.set_type(result_type_id);
834        instruction.set_result(id);
835        instruction.add_operand(query);
836        instruction.add_operand(intersection);
837        instruction
838    }
839
840    pub(super) fn ray_query_get_intersection(
841        op: Op,
842        result_type_id: Word,
843        id: Word,
844        query: Word,
845        intersection: Word,
846    ) -> Self {
847        let mut instruction = Self::new(op);
848        instruction.set_type(result_type_id);
849        instruction.set_result(id);
850        instruction.add_operand(query);
851        instruction.add_operand(intersection);
852        instruction
853    }
854
855    pub(super) fn ray_query_get_t_min(result_type_id: Word, id: Word, query: Word) -> Self {
856        let mut instruction = Self::new(Op::RayQueryGetRayTMinKHR);
857        instruction.set_type(result_type_id);
858        instruction.set_result(id);
859        instruction.add_operand(query);
860        instruction
861    }
862
863    pub(super) fn ray_query_terminate(query: Word) -> Self {
864        let mut instruction = Self::new(Op::RayQueryTerminateKHR);
865        instruction.add_operand(query);
866        instruction
867    }
868
869    //
870    //  Conversion Instructions
871    //
872    pub(super) fn unary(op: Op, result_type_id: Word, id: Word, value: Word) -> Self {
873        let mut instruction = Self::new(op);
874        instruction.set_type(result_type_id);
875        instruction.set_result(id);
876        instruction.add_operand(value);
877        instruction
878    }
879
880    //
881    //  Composite Instructions
882    //
883
884    pub(super) fn composite_construct(
885        result_type_id: Word,
886        id: Word,
887        constituent_ids: &[Word],
888    ) -> Self {
889        let mut instruction = Self::new(Op::CompositeConstruct);
890        instruction.set_type(result_type_id);
891        instruction.set_result(id);
892
893        for constituent_id in constituent_ids {
894            instruction.add_operand(*constituent_id);
895        }
896
897        instruction
898    }
899
900    pub(super) fn composite_extract(
901        result_type_id: Word,
902        id: Word,
903        composite_id: Word,
904        indices: &[Word],
905    ) -> Self {
906        let mut instruction = Self::new(Op::CompositeExtract);
907        instruction.set_type(result_type_id);
908        instruction.set_result(id);
909
910        instruction.add_operand(composite_id);
911        for index in indices {
912            instruction.add_operand(*index);
913        }
914
915        instruction
916    }
917
918    pub(super) fn vector_extract_dynamic(
919        result_type_id: Word,
920        id: Word,
921        vector_id: Word,
922        index_id: Word,
923    ) -> Self {
924        let mut instruction = Self::new(Op::VectorExtractDynamic);
925        instruction.set_type(result_type_id);
926        instruction.set_result(id);
927
928        instruction.add_operand(vector_id);
929        instruction.add_operand(index_id);
930
931        instruction
932    }
933
934    pub(super) fn vector_shuffle(
935        result_type_id: Word,
936        id: Word,
937        v1_id: Word,
938        v2_id: Word,
939        components: &[Word],
940    ) -> Self {
941        let mut instruction = Self::new(Op::VectorShuffle);
942        instruction.set_type(result_type_id);
943        instruction.set_result(id);
944        instruction.add_operand(v1_id);
945        instruction.add_operand(v2_id);
946
947        for &component in components {
948            instruction.add_operand(component);
949        }
950
951        instruction
952    }
953
954    //
955    // Arithmetic Instructions
956    //
957    pub(super) fn binary(
958        op: Op,
959        result_type_id: Word,
960        id: Word,
961        operand_1: Word,
962        operand_2: Word,
963    ) -> Self {
964        let mut instruction = Self::new(op);
965        instruction.set_type(result_type_id);
966        instruction.set_result(id);
967        instruction.add_operand(operand_1);
968        instruction.add_operand(operand_2);
969        instruction
970    }
971
972    pub(super) fn ternary(
973        op: Op,
974        result_type_id: Word,
975        id: Word,
976        operand_1: Word,
977        operand_2: Word,
978        operand_3: Word,
979    ) -> Self {
980        let mut instruction = Self::new(op);
981        instruction.set_type(result_type_id);
982        instruction.set_result(id);
983        instruction.add_operand(operand_1);
984        instruction.add_operand(operand_2);
985        instruction.add_operand(operand_3);
986        instruction
987    }
988
989    pub(super) fn quaternary(
990        op: Op,
991        result_type_id: Word,
992        id: Word,
993        operand_1: Word,
994        operand_2: Word,
995        operand_3: Word,
996        operand_4: Word,
997    ) -> Self {
998        let mut instruction = Self::new(op);
999        instruction.set_type(result_type_id);
1000        instruction.set_result(id);
1001        instruction.add_operand(operand_1);
1002        instruction.add_operand(operand_2);
1003        instruction.add_operand(operand_3);
1004        instruction.add_operand(operand_4);
1005        instruction
1006    }
1007
1008    pub(super) fn relational(op: Op, result_type_id: Word, id: Word, expr_id: Word) -> Self {
1009        let mut instruction = Self::new(op);
1010        instruction.set_type(result_type_id);
1011        instruction.set_result(id);
1012        instruction.add_operand(expr_id);
1013        instruction
1014    }
1015
1016    pub(super) fn atomic_binary(
1017        op: Op,
1018        result_type_id: Word,
1019        id: Word,
1020        pointer: Word,
1021        scope_id: Word,
1022        semantics_id: Word,
1023        value: Word,
1024    ) -> Self {
1025        let mut instruction = Self::new(op);
1026        instruction.set_type(result_type_id);
1027        instruction.set_result(id);
1028        instruction.add_operand(pointer);
1029        instruction.add_operand(scope_id);
1030        instruction.add_operand(semantics_id);
1031        instruction.add_operand(value);
1032        instruction
1033    }
1034
1035    //
1036    // Bit Instructions
1037    //
1038
1039    //
1040    // Relational and Logical Instructions
1041    //
1042
1043    //
1044    // Derivative Instructions
1045    //
1046
1047    pub(super) fn derivative(op: Op, result_type_id: Word, id: Word, expr_id: Word) -> Self {
1048        let mut instruction = Self::new(op);
1049        instruction.set_type(result_type_id);
1050        instruction.set_result(id);
1051        instruction.add_operand(expr_id);
1052        instruction
1053    }
1054
1055    //
1056    // Control-Flow Instructions
1057    //
1058
1059    pub(super) fn phi(
1060        result_type_id: Word,
1061        result_id: Word,
1062        var_parent_pairs: &[(Word, Word)],
1063    ) -> Self {
1064        let mut instruction = Self::new(Op::Phi);
1065        instruction.add_operand(result_type_id);
1066        instruction.add_operand(result_id);
1067        for &(variable, parent) in var_parent_pairs {
1068            instruction.add_operand(variable);
1069            instruction.add_operand(parent);
1070        }
1071        instruction
1072    }
1073
1074    pub(super) fn selection_merge(
1075        merge_id: Word,
1076        selection_control: spirv::SelectionControl,
1077    ) -> Self {
1078        let mut instruction = Self::new(Op::SelectionMerge);
1079        instruction.add_operand(merge_id);
1080        instruction.add_operand(selection_control.bits());
1081        instruction
1082    }
1083
1084    pub(super) fn loop_merge(
1085        merge_id: Word,
1086        continuing_id: Word,
1087        selection_control: spirv::SelectionControl,
1088    ) -> Self {
1089        let mut instruction = Self::new(Op::LoopMerge);
1090        instruction.add_operand(merge_id);
1091        instruction.add_operand(continuing_id);
1092        instruction.add_operand(selection_control.bits());
1093        instruction
1094    }
1095
1096    pub(super) fn label(id: Word) -> Self {
1097        let mut instruction = Self::new(Op::Label);
1098        instruction.set_result(id);
1099        instruction
1100    }
1101
1102    pub(super) fn branch(id: Word) -> Self {
1103        let mut instruction = Self::new(Op::Branch);
1104        instruction.add_operand(id);
1105        instruction
1106    }
1107
1108    // TODO Branch Weights not implemented.
1109    pub(super) fn branch_conditional(
1110        condition_id: Word,
1111        true_label: Word,
1112        false_label: Word,
1113    ) -> Self {
1114        let mut instruction = Self::new(Op::BranchConditional);
1115        instruction.add_operand(condition_id);
1116        instruction.add_operand(true_label);
1117        instruction.add_operand(false_label);
1118        instruction
1119    }
1120
1121    pub(super) fn switch(selector_id: Word, default_id: Word, cases: &[Case]) -> Self {
1122        let mut instruction = Self::new(Op::Switch);
1123        instruction.add_operand(selector_id);
1124        instruction.add_operand(default_id);
1125        for case in cases {
1126            instruction.add_operand(case.value);
1127            instruction.add_operand(case.label_id);
1128        }
1129        instruction
1130    }
1131
1132    pub(super) fn select(
1133        result_type_id: Word,
1134        id: Word,
1135        condition_id: Word,
1136        accept_id: Word,
1137        reject_id: Word,
1138    ) -> Self {
1139        let mut instruction = Self::new(Op::Select);
1140        instruction.add_operand(result_type_id);
1141        instruction.add_operand(id);
1142        instruction.add_operand(condition_id);
1143        instruction.add_operand(accept_id);
1144        instruction.add_operand(reject_id);
1145        instruction
1146    }
1147
1148    pub(super) const fn kill() -> Self {
1149        Self::new(Op::Kill)
1150    }
1151
1152    pub(super) const fn return_void() -> Self {
1153        Self::new(Op::Return)
1154    }
1155
1156    pub(super) fn return_value(value_id: Word) -> Self {
1157        let mut instruction = Self::new(Op::ReturnValue);
1158        instruction.add_operand(value_id);
1159        instruction
1160    }
1161
1162    //
1163    //  Atomic Instructions
1164    //
1165
1166    //
1167    //  Primitive Instructions
1168    //
1169
1170    // Barriers
1171
1172    pub(super) fn control_barrier(
1173        exec_scope_id: Word,
1174        mem_scope_id: Word,
1175        semantics_id: Word,
1176    ) -> Self {
1177        let mut instruction = Self::new(Op::ControlBarrier);
1178        instruction.add_operand(exec_scope_id);
1179        instruction.add_operand(mem_scope_id);
1180        instruction.add_operand(semantics_id);
1181        instruction
1182    }
1183    pub(super) fn memory_barrier(mem_scope_id: Word, semantics_id: Word) -> Self {
1184        let mut instruction = Self::new(Op::MemoryBarrier);
1185        instruction.add_operand(mem_scope_id);
1186        instruction.add_operand(semantics_id);
1187        instruction
1188    }
1189
1190    // Group Instructions
1191
1192    pub(super) fn group_non_uniform_ballot(
1193        result_type_id: Word,
1194        id: Word,
1195        exec_scope_id: Word,
1196        predicate: Word,
1197    ) -> Self {
1198        let mut instruction = Self::new(Op::GroupNonUniformBallot);
1199        instruction.set_type(result_type_id);
1200        instruction.set_result(id);
1201        instruction.add_operand(exec_scope_id);
1202        instruction.add_operand(predicate);
1203
1204        instruction
1205    }
1206    pub(super) fn group_non_uniform_broadcast_first(
1207        result_type_id: Word,
1208        id: Word,
1209        exec_scope_id: Word,
1210        value: Word,
1211    ) -> Self {
1212        let mut instruction = Self::new(Op::GroupNonUniformBroadcastFirst);
1213        instruction.set_type(result_type_id);
1214        instruction.set_result(id);
1215        instruction.add_operand(exec_scope_id);
1216        instruction.add_operand(value);
1217
1218        instruction
1219    }
1220    pub(super) fn group_non_uniform_gather(
1221        op: Op,
1222        result_type_id: Word,
1223        id: Word,
1224        exec_scope_id: Word,
1225        value: Word,
1226        index: Word,
1227    ) -> Self {
1228        let mut instruction = Self::new(op);
1229        instruction.set_type(result_type_id);
1230        instruction.set_result(id);
1231        instruction.add_operand(exec_scope_id);
1232        instruction.add_operand(value);
1233        instruction.add_operand(index);
1234
1235        instruction
1236    }
1237    pub(super) fn group_non_uniform_arithmetic(
1238        op: Op,
1239        result_type_id: Word,
1240        id: Word,
1241        exec_scope_id: Word,
1242        group_op: Option<spirv::GroupOperation>,
1243        value: Word,
1244    ) -> Self {
1245        let mut instruction = Self::new(op);
1246        instruction.set_type(result_type_id);
1247        instruction.set_result(id);
1248        instruction.add_operand(exec_scope_id);
1249        if let Some(group_op) = group_op {
1250            instruction.add_operand(group_op as u32);
1251        }
1252        instruction.add_operand(value);
1253
1254        instruction
1255    }
1256    pub(super) fn group_non_uniform_quad_swap(
1257        result_type_id: Word,
1258        id: Word,
1259        exec_scope_id: Word,
1260        value: Word,
1261        direction: Word,
1262    ) -> Self {
1263        let mut instruction = Self::new(Op::GroupNonUniformQuadSwap);
1264        instruction.set_type(result_type_id);
1265        instruction.set_result(id);
1266        instruction.add_operand(exec_scope_id);
1267        instruction.add_operand(value);
1268        instruction.add_operand(direction);
1269
1270        instruction
1271    }
1272
1273    // Cooperative operations
1274    pub(super) fn coop_load(
1275        result_type_id: Word,
1276        id: Word,
1277        pointer_id: Word,
1278        layout_id: Word,
1279        stride_id: Word,
1280    ) -> Self {
1281        let mut instruction = Self::new(Op::CooperativeMatrixLoadKHR);
1282        instruction.set_type(result_type_id);
1283        instruction.set_result(id);
1284        instruction.add_operand(pointer_id);
1285        instruction.add_operand(layout_id);
1286        instruction.add_operand(stride_id);
1287        instruction
1288    }
1289    pub(super) fn coop_store(id: Word, pointer_id: Word, layout_id: Word, stride_id: Word) -> Self {
1290        let mut instruction = Self::new(Op::CooperativeMatrixStoreKHR);
1291        instruction.add_operand(pointer_id);
1292        instruction.add_operand(id);
1293        instruction.add_operand(layout_id);
1294        instruction.add_operand(stride_id);
1295        instruction
1296    }
1297    pub(super) fn coop_mul_add(result_type_id: Word, id: Word, a: Word, b: Word, c: Word) -> Self {
1298        let mut instruction = Self::new(Op::CooperativeMatrixMulAddKHR);
1299        instruction.set_type(result_type_id);
1300        instruction.set_result(id);
1301        instruction.add_operand(a);
1302        instruction.add_operand(b);
1303        instruction.add_operand(c);
1304
1305        instruction
1306    }
1307}
1308
1309impl From<crate::StorageFormat> for spirv::ImageFormat {
1310    fn from(format: crate::StorageFormat) -> Self {
1311        use crate::StorageFormat as Sf;
1312        match format {
1313            Sf::R8Unorm => Self::R8,
1314            Sf::R8Snorm => Self::R8Snorm,
1315            Sf::R8Uint => Self::R8ui,
1316            Sf::R8Sint => Self::R8i,
1317            Sf::R16Uint => Self::R16ui,
1318            Sf::R16Sint => Self::R16i,
1319            Sf::R16Float => Self::R16f,
1320            Sf::Rg8Unorm => Self::Rg8,
1321            Sf::Rg8Snorm => Self::Rg8Snorm,
1322            Sf::Rg8Uint => Self::Rg8ui,
1323            Sf::Rg8Sint => Self::Rg8i,
1324            Sf::R32Uint => Self::R32ui,
1325            Sf::R32Sint => Self::R32i,
1326            Sf::R32Float => Self::R32f,
1327            Sf::Rg16Uint => Self::Rg16ui,
1328            Sf::Rg16Sint => Self::Rg16i,
1329            Sf::Rg16Float => Self::Rg16f,
1330            Sf::Rgba8Unorm => Self::Rgba8,
1331            Sf::Rgba8Snorm => Self::Rgba8Snorm,
1332            Sf::Rgba8Uint => Self::Rgba8ui,
1333            Sf::Rgba8Sint => Self::Rgba8i,
1334            Sf::Bgra8Unorm => Self::Unknown,
1335            Sf::Rgb10a2Uint => Self::Rgb10a2ui,
1336            Sf::Rgb10a2Unorm => Self::Rgb10A2,
1337            Sf::Rg11b10Ufloat => Self::R11fG11fB10f,
1338            Sf::R64Uint => Self::R64ui,
1339            Sf::Rg32Uint => Self::Rg32ui,
1340            Sf::Rg32Sint => Self::Rg32i,
1341            Sf::Rg32Float => Self::Rg32f,
1342            Sf::Rgba16Uint => Self::Rgba16ui,
1343            Sf::Rgba16Sint => Self::Rgba16i,
1344            Sf::Rgba16Float => Self::Rgba16f,
1345            Sf::Rgba32Uint => Self::Rgba32ui,
1346            Sf::Rgba32Sint => Self::Rgba32i,
1347            Sf::Rgba32Float => Self::Rgba32f,
1348            Sf::R16Unorm => Self::R16,
1349            Sf::R16Snorm => Self::R16Snorm,
1350            Sf::Rg16Unorm => Self::Rg16,
1351            Sf::Rg16Snorm => Self::Rg16Snorm,
1352            Sf::Rgba16Unorm => Self::Rgba16,
1353            Sf::Rgba16Snorm => Self::Rgba16Snorm,
1354        }
1355    }
1356}
1357
1358impl From<crate::ImageDimension> for spirv::Dim {
1359    fn from(dim: crate::ImageDimension) -> Self {
1360        use crate::ImageDimension as Id;
1361        match dim {
1362            Id::D1 => Self::Dim1D,
1363            Id::D2 => Self::Dim2D,
1364            Id::D3 => Self::Dim3D,
1365            Id::Cube => Self::DimCube,
1366        }
1367    }
1368}
1369
1370impl From<crate::CooperativeRole> for spirv::CooperativeMatrixUse {
1371    fn from(role: crate::CooperativeRole) -> Self {
1372        match role {
1373            crate::CooperativeRole::A => Self::MatrixAKHR,
1374            crate::CooperativeRole::B => Self::MatrixBKHR,
1375            crate::CooperativeRole::C => Self::MatrixAccumulatorKHR,
1376        }
1377    }
1378}