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