naga/back/spv/
instructions.rs

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