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