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_texel_pointer(
706        result_type_id: Word,
707        id: Word,
708        image: Word,
709        coordinates: Word,
710        sample: Word,
711    ) -> Self {
712        let mut instruction = Self::new(Op::ImageTexelPointer);
713        instruction.set_type(result_type_id);
714        instruction.set_result(id);
715        instruction.add_operand(image);
716        instruction.add_operand(coordinates);
717        instruction.add_operand(sample);
718        instruction
719    }
720
721    pub(super) fn image_atomic(
722        op: Op,
723        result_type_id: Word,
724        id: Word,
725        pointer: Word,
726        scope_id: Word,
727        semantics_id: Word,
728        value: Word,
729    ) -> Self {
730        let mut instruction = Self::new(op);
731        instruction.set_type(result_type_id);
732        instruction.set_result(id);
733        instruction.add_operand(pointer);
734        instruction.add_operand(scope_id);
735        instruction.add_operand(semantics_id);
736        instruction.add_operand(value);
737        instruction
738    }
739
740    pub(super) fn image_query(op: Op, result_type_id: Word, id: Word, image: Word) -> Self {
741        let mut instruction = Self::new(op);
742        instruction.set_type(result_type_id);
743        instruction.set_result(id);
744        instruction.add_operand(image);
745        instruction
746    }
747
748    //
749    //  Ray Query Instructions
750    //
751    #[allow(clippy::too_many_arguments)]
752    pub(super) fn ray_query_initialize(
753        query: Word,
754        acceleration_structure: Word,
755        ray_flags: Word,
756        cull_mask: Word,
757        ray_origin: Word,
758        ray_tmin: Word,
759        ray_dir: Word,
760        ray_tmax: Word,
761    ) -> Self {
762        let mut instruction = Self::new(Op::RayQueryInitializeKHR);
763        instruction.add_operand(query);
764        instruction.add_operand(acceleration_structure);
765        instruction.add_operand(ray_flags);
766        instruction.add_operand(cull_mask);
767        instruction.add_operand(ray_origin);
768        instruction.add_operand(ray_tmin);
769        instruction.add_operand(ray_dir);
770        instruction.add_operand(ray_tmax);
771        instruction
772    }
773
774    pub(super) fn ray_query_proceed(result_type_id: Word, id: Word, query: Word) -> Self {
775        let mut instruction = Self::new(Op::RayQueryProceedKHR);
776        instruction.set_type(result_type_id);
777        instruction.set_result(id);
778        instruction.add_operand(query);
779        instruction
780    }
781
782    pub(super) fn ray_query_get_intersection(
783        op: Op,
784        result_type_id: Word,
785        id: Word,
786        query: Word,
787        intersection: Word,
788    ) -> Self {
789        let mut instruction = Self::new(op);
790        instruction.set_type(result_type_id);
791        instruction.set_result(id);
792        instruction.add_operand(query);
793        instruction.add_operand(intersection);
794        instruction
795    }
796
797    //
798    //  Conversion Instructions
799    //
800    pub(super) fn unary(op: Op, result_type_id: Word, id: Word, value: Word) -> Self {
801        let mut instruction = Self::new(op);
802        instruction.set_type(result_type_id);
803        instruction.set_result(id);
804        instruction.add_operand(value);
805        instruction
806    }
807
808    //
809    //  Composite Instructions
810    //
811
812    pub(super) fn composite_construct(
813        result_type_id: Word,
814        id: Word,
815        constituent_ids: &[Word],
816    ) -> Self {
817        let mut instruction = Self::new(Op::CompositeConstruct);
818        instruction.set_type(result_type_id);
819        instruction.set_result(id);
820
821        for constituent_id in constituent_ids {
822            instruction.add_operand(*constituent_id);
823        }
824
825        instruction
826    }
827
828    pub(super) fn composite_extract(
829        result_type_id: Word,
830        id: Word,
831        composite_id: Word,
832        indices: &[Word],
833    ) -> Self {
834        let mut instruction = Self::new(Op::CompositeExtract);
835        instruction.set_type(result_type_id);
836        instruction.set_result(id);
837
838        instruction.add_operand(composite_id);
839        for index in indices {
840            instruction.add_operand(*index);
841        }
842
843        instruction
844    }
845
846    pub(super) fn vector_extract_dynamic(
847        result_type_id: Word,
848        id: Word,
849        vector_id: Word,
850        index_id: Word,
851    ) -> Self {
852        let mut instruction = Self::new(Op::VectorExtractDynamic);
853        instruction.set_type(result_type_id);
854        instruction.set_result(id);
855
856        instruction.add_operand(vector_id);
857        instruction.add_operand(index_id);
858
859        instruction
860    }
861
862    pub(super) fn vector_shuffle(
863        result_type_id: Word,
864        id: Word,
865        v1_id: Word,
866        v2_id: Word,
867        components: &[Word],
868    ) -> Self {
869        let mut instruction = Self::new(Op::VectorShuffle);
870        instruction.set_type(result_type_id);
871        instruction.set_result(id);
872        instruction.add_operand(v1_id);
873        instruction.add_operand(v2_id);
874
875        for &component in components {
876            instruction.add_operand(component);
877        }
878
879        instruction
880    }
881
882    //
883    // Arithmetic Instructions
884    //
885    pub(super) fn binary(
886        op: Op,
887        result_type_id: Word,
888        id: Word,
889        operand_1: Word,
890        operand_2: Word,
891    ) -> Self {
892        let mut instruction = Self::new(op);
893        instruction.set_type(result_type_id);
894        instruction.set_result(id);
895        instruction.add_operand(operand_1);
896        instruction.add_operand(operand_2);
897        instruction
898    }
899
900    pub(super) fn ternary(
901        op: Op,
902        result_type_id: Word,
903        id: Word,
904        operand_1: Word,
905        operand_2: Word,
906        operand_3: Word,
907    ) -> Self {
908        let mut instruction = Self::new(op);
909        instruction.set_type(result_type_id);
910        instruction.set_result(id);
911        instruction.add_operand(operand_1);
912        instruction.add_operand(operand_2);
913        instruction.add_operand(operand_3);
914        instruction
915    }
916
917    pub(super) fn quaternary(
918        op: Op,
919        result_type_id: Word,
920        id: Word,
921        operand_1: Word,
922        operand_2: Word,
923        operand_3: Word,
924        operand_4: Word,
925    ) -> Self {
926        let mut instruction = Self::new(op);
927        instruction.set_type(result_type_id);
928        instruction.set_result(id);
929        instruction.add_operand(operand_1);
930        instruction.add_operand(operand_2);
931        instruction.add_operand(operand_3);
932        instruction.add_operand(operand_4);
933        instruction
934    }
935
936    pub(super) fn relational(op: Op, result_type_id: Word, id: Word, expr_id: Word) -> Self {
937        let mut instruction = Self::new(op);
938        instruction.set_type(result_type_id);
939        instruction.set_result(id);
940        instruction.add_operand(expr_id);
941        instruction
942    }
943
944    pub(super) fn atomic_binary(
945        op: Op,
946        result_type_id: Word,
947        id: Word,
948        pointer: Word,
949        scope_id: Word,
950        semantics_id: Word,
951        value: Word,
952    ) -> Self {
953        let mut instruction = Self::new(op);
954        instruction.set_type(result_type_id);
955        instruction.set_result(id);
956        instruction.add_operand(pointer);
957        instruction.add_operand(scope_id);
958        instruction.add_operand(semantics_id);
959        instruction.add_operand(value);
960        instruction
961    }
962
963    //
964    // Bit Instructions
965    //
966
967    //
968    // Relational and Logical Instructions
969    //
970
971    //
972    // Derivative Instructions
973    //
974
975    pub(super) fn derivative(op: Op, result_type_id: Word, id: Word, expr_id: Word) -> Self {
976        let mut instruction = Self::new(op);
977        instruction.set_type(result_type_id);
978        instruction.set_result(id);
979        instruction.add_operand(expr_id);
980        instruction
981    }
982
983    //
984    // Control-Flow Instructions
985    //
986
987    pub(super) fn phi(
988        result_type_id: Word,
989        result_id: Word,
990        var_parent_pairs: &[(Word, Word)],
991    ) -> Self {
992        let mut instruction = Self::new(Op::Phi);
993        instruction.add_operand(result_type_id);
994        instruction.add_operand(result_id);
995        for &(variable, parent) in var_parent_pairs {
996            instruction.add_operand(variable);
997            instruction.add_operand(parent);
998        }
999        instruction
1000    }
1001
1002    pub(super) fn selection_merge(
1003        merge_id: Word,
1004        selection_control: spirv::SelectionControl,
1005    ) -> Self {
1006        let mut instruction = Self::new(Op::SelectionMerge);
1007        instruction.add_operand(merge_id);
1008        instruction.add_operand(selection_control.bits());
1009        instruction
1010    }
1011
1012    pub(super) fn loop_merge(
1013        merge_id: Word,
1014        continuing_id: Word,
1015        selection_control: spirv::SelectionControl,
1016    ) -> Self {
1017        let mut instruction = Self::new(Op::LoopMerge);
1018        instruction.add_operand(merge_id);
1019        instruction.add_operand(continuing_id);
1020        instruction.add_operand(selection_control.bits());
1021        instruction
1022    }
1023
1024    pub(super) fn label(id: Word) -> Self {
1025        let mut instruction = Self::new(Op::Label);
1026        instruction.set_result(id);
1027        instruction
1028    }
1029
1030    pub(super) fn branch(id: Word) -> Self {
1031        let mut instruction = Self::new(Op::Branch);
1032        instruction.add_operand(id);
1033        instruction
1034    }
1035
1036    // TODO Branch Weights not implemented.
1037    pub(super) fn branch_conditional(
1038        condition_id: Word,
1039        true_label: Word,
1040        false_label: Word,
1041    ) -> Self {
1042        let mut instruction = Self::new(Op::BranchConditional);
1043        instruction.add_operand(condition_id);
1044        instruction.add_operand(true_label);
1045        instruction.add_operand(false_label);
1046        instruction
1047    }
1048
1049    pub(super) fn switch(selector_id: Word, default_id: Word, cases: &[Case]) -> Self {
1050        let mut instruction = Self::new(Op::Switch);
1051        instruction.add_operand(selector_id);
1052        instruction.add_operand(default_id);
1053        for case in cases {
1054            instruction.add_operand(case.value);
1055            instruction.add_operand(case.label_id);
1056        }
1057        instruction
1058    }
1059
1060    pub(super) fn select(
1061        result_type_id: Word,
1062        id: Word,
1063        condition_id: Word,
1064        accept_id: Word,
1065        reject_id: Word,
1066    ) -> Self {
1067        let mut instruction = Self::new(Op::Select);
1068        instruction.add_operand(result_type_id);
1069        instruction.add_operand(id);
1070        instruction.add_operand(condition_id);
1071        instruction.add_operand(accept_id);
1072        instruction.add_operand(reject_id);
1073        instruction
1074    }
1075
1076    pub(super) const fn kill() -> Self {
1077        Self::new(Op::Kill)
1078    }
1079
1080    pub(super) const fn return_void() -> Self {
1081        Self::new(Op::Return)
1082    }
1083
1084    pub(super) fn return_value(value_id: Word) -> Self {
1085        let mut instruction = Self::new(Op::ReturnValue);
1086        instruction.add_operand(value_id);
1087        instruction
1088    }
1089
1090    //
1091    //  Atomic Instructions
1092    //
1093
1094    //
1095    //  Primitive Instructions
1096    //
1097
1098    // Barriers
1099
1100    pub(super) fn control_barrier(
1101        exec_scope_id: Word,
1102        mem_scope_id: Word,
1103        semantics_id: Word,
1104    ) -> Self {
1105        let mut instruction = Self::new(Op::ControlBarrier);
1106        instruction.add_operand(exec_scope_id);
1107        instruction.add_operand(mem_scope_id);
1108        instruction.add_operand(semantics_id);
1109        instruction
1110    }
1111
1112    // Group Instructions
1113
1114    pub(super) fn group_non_uniform_ballot(
1115        result_type_id: Word,
1116        id: Word,
1117        exec_scope_id: Word,
1118        predicate: Word,
1119    ) -> Self {
1120        let mut instruction = Self::new(Op::GroupNonUniformBallot);
1121        instruction.set_type(result_type_id);
1122        instruction.set_result(id);
1123        instruction.add_operand(exec_scope_id);
1124        instruction.add_operand(predicate);
1125
1126        instruction
1127    }
1128    pub(super) fn group_non_uniform_broadcast_first(
1129        result_type_id: Word,
1130        id: Word,
1131        exec_scope_id: Word,
1132        value: Word,
1133    ) -> Self {
1134        let mut instruction = Self::new(Op::GroupNonUniformBroadcastFirst);
1135        instruction.set_type(result_type_id);
1136        instruction.set_result(id);
1137        instruction.add_operand(exec_scope_id);
1138        instruction.add_operand(value);
1139
1140        instruction
1141    }
1142    pub(super) fn group_non_uniform_gather(
1143        op: Op,
1144        result_type_id: Word,
1145        id: Word,
1146        exec_scope_id: Word,
1147        value: Word,
1148        index: Word,
1149    ) -> Self {
1150        let mut instruction = Self::new(op);
1151        instruction.set_type(result_type_id);
1152        instruction.set_result(id);
1153        instruction.add_operand(exec_scope_id);
1154        instruction.add_operand(value);
1155        instruction.add_operand(index);
1156
1157        instruction
1158    }
1159    pub(super) fn group_non_uniform_arithmetic(
1160        op: Op,
1161        result_type_id: Word,
1162        id: Word,
1163        exec_scope_id: Word,
1164        group_op: Option<spirv::GroupOperation>,
1165        value: Word,
1166    ) -> Self {
1167        let mut instruction = Self::new(op);
1168        instruction.set_type(result_type_id);
1169        instruction.set_result(id);
1170        instruction.add_operand(exec_scope_id);
1171        if let Some(group_op) = group_op {
1172            instruction.add_operand(group_op as u32);
1173        }
1174        instruction.add_operand(value);
1175
1176        instruction
1177    }
1178}
1179
1180impl From<crate::StorageFormat> for spirv::ImageFormat {
1181    fn from(format: crate::StorageFormat) -> Self {
1182        use crate::StorageFormat as Sf;
1183        match format {
1184            Sf::R8Unorm => Self::R8,
1185            Sf::R8Snorm => Self::R8Snorm,
1186            Sf::R8Uint => Self::R8ui,
1187            Sf::R8Sint => Self::R8i,
1188            Sf::R16Uint => Self::R16ui,
1189            Sf::R16Sint => Self::R16i,
1190            Sf::R16Float => Self::R16f,
1191            Sf::Rg8Unorm => Self::Rg8,
1192            Sf::Rg8Snorm => Self::Rg8Snorm,
1193            Sf::Rg8Uint => Self::Rg8ui,
1194            Sf::Rg8Sint => Self::Rg8i,
1195            Sf::R32Uint => Self::R32ui,
1196            Sf::R32Sint => Self::R32i,
1197            Sf::R32Float => Self::R32f,
1198            Sf::Rg16Uint => Self::Rg16ui,
1199            Sf::Rg16Sint => Self::Rg16i,
1200            Sf::Rg16Float => Self::Rg16f,
1201            Sf::Rgba8Unorm => Self::Rgba8,
1202            Sf::Rgba8Snorm => Self::Rgba8Snorm,
1203            Sf::Rgba8Uint => Self::Rgba8ui,
1204            Sf::Rgba8Sint => Self::Rgba8i,
1205            Sf::Bgra8Unorm => Self::Unknown,
1206            Sf::Rgb10a2Uint => Self::Rgb10a2ui,
1207            Sf::Rgb10a2Unorm => Self::Rgb10A2,
1208            Sf::Rg11b10Ufloat => Self::R11fG11fB10f,
1209            Sf::R64Uint => Self::R64ui,
1210            Sf::Rg32Uint => Self::Rg32ui,
1211            Sf::Rg32Sint => Self::Rg32i,
1212            Sf::Rg32Float => Self::Rg32f,
1213            Sf::Rgba16Uint => Self::Rgba16ui,
1214            Sf::Rgba16Sint => Self::Rgba16i,
1215            Sf::Rgba16Float => Self::Rgba16f,
1216            Sf::Rgba32Uint => Self::Rgba32ui,
1217            Sf::Rgba32Sint => Self::Rgba32i,
1218            Sf::Rgba32Float => Self::Rgba32f,
1219            Sf::R16Unorm => Self::R16,
1220            Sf::R16Snorm => Self::R16Snorm,
1221            Sf::Rg16Unorm => Self::Rg16,
1222            Sf::Rg16Snorm => Self::Rg16Snorm,
1223            Sf::Rgba16Unorm => Self::Rgba16,
1224            Sf::Rgba16Snorm => Self::Rgba16Snorm,
1225        }
1226    }
1227}
1228
1229impl From<crate::ImageDimension> for spirv::Dim {
1230    fn from(dim: crate::ImageDimension) -> Self {
1231        use crate::ImageDimension as Id;
1232        match dim {
1233            Id::D1 => Self::Dim1D,
1234            Id::D2 => Self::Dim2D,
1235            Id::D3 => Self::Dim3D,
1236            Id::Cube => Self::DimCube,
1237        }
1238    }
1239}