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