1#![allow(clippy::too_many_arguments)]
2
3use crate::dr;
4use crate::spirv;
5
6use super::Error;
7use std::result;
8
9type BuildResult<T> = result::Result<T, Error>;
10
11#[derive(Default)]
85pub struct Builder {
86 module: dr::Module,
87 next_id: u32,
88 selected_function: Option<usize>,
89 selected_block: Option<usize>,
90}
91
92pub enum InsertPoint {
93 Begin,
94 End,
95 FromBegin(usize),
96 FromEnd(usize),
97}
98
99impl Builder {
100 pub fn new() -> Builder {
102 Builder {
103 module: dr::Module::new(),
104 next_id: 1,
105 selected_function: None,
106 selected_block: None,
107 }
108 }
109
110 pub fn new_from_module(module: dr::Module) -> Builder {
112 let next_id = module
113 .header
114 .as_ref()
115 .map(|h| h.bound)
116 .expect("Expecting ModuleHeader with valid bound");
117
118 Builder {
119 module,
120 next_id,
121 selected_function: None,
122 selected_block: None,
123 }
124 }
125
126 pub fn insert_into_block(
127 &mut self,
128 insert_point: InsertPoint,
129 inst: dr::Instruction,
130 ) -> BuildResult<()> {
131 let (selected_function, selected_block) =
132 match (self.selected_function, self.selected_block) {
133 (Some(f), Some(b)) => (f, b),
134 _ => return Err(Error::DetachedInstruction(Some(inst))),
135 };
136
137 let block = &mut self.module.functions[selected_function].blocks[selected_block];
138
139 match insert_point {
140 InsertPoint::End => block.instructions.push(inst),
141 InsertPoint::Begin => block.instructions.insert(0, inst),
142 InsertPoint::FromEnd(offset) => {
143 let end = block.instructions.len();
144 block.instructions.insert(end - offset, inst)
145 }
146 InsertPoint::FromBegin(offset) => block.instructions.insert(offset, inst),
147 }
148
149 Ok(())
150 }
151
152 pub fn insert_types_global_values(&mut self, insert_point: InsertPoint, inst: dr::Instruction) {
153 match insert_point {
154 InsertPoint::End => self.module.types_global_values.push(inst),
155 InsertPoint::Begin => self.module.types_global_values.insert(0, inst),
156 InsertPoint::FromEnd(offset) => {
157 let end = self.module.types_global_values.len();
158 self.module.types_global_values.insert(end - offset, inst)
159 }
160 InsertPoint::FromBegin(offset) => self.module.types_global_values.insert(offset, inst),
161 }
162 }
163
164 pub fn pop_instruction(&mut self) -> BuildResult<dr::Instruction> {
165 let (selected_function, selected_block) =
166 match (self.selected_function, self.selected_block) {
167 (Some(f), Some(b)) => (f, b),
168 _ => return Err(Error::DetachedInstruction(None)),
169 };
170
171 let block = &mut self.module.functions[selected_function].blocks[selected_block];
172
173 block.instructions.pop().ok_or(Error::EmptyInstructionList)
174 }
175
176 pub fn set_version(&mut self, major: u8, minor: u8) {
181 if self.module.header.is_none() {
182 self.module.header = Some(dr::ModuleHeader::new(0));
184 }
185 self.module
186 .header
187 .as_mut()
188 .unwrap()
189 .set_version(major, minor);
190 }
191
192 pub fn version(&self) -> Option<(u8, u8)> {
194 self.module.header.as_ref().map(|h| h.version())
195 }
196
197 pub fn module(self) -> dr::Module {
199 let mut module = self.module;
200
201 match &mut module.header {
202 Some(header) => header.bound = self.next_id,
203 None => module.header = Some(dr::ModuleHeader::new(self.next_id)),
204 }
205
206 module
207 }
208
209 pub fn module_ref(&self) -> &dr::Module {
211 &self.module
212 }
213
214 pub fn module_mut(&mut self) -> &mut dr::Module {
216 &mut self.module
217 }
218
219 pub fn selected_function(&self) -> Option<usize> {
220 self.selected_function
221 }
222
223 pub fn selected_block(&self) -> Option<usize> {
224 self.selected_block
225 }
226
227 pub fn id(&mut self) -> spirv::Word {
229 let id = self.next_id;
230 self.next_id += 1;
231 id
232 }
233
234 pub fn dedup_insert_type(&mut self, inst: &dr::Instruction) -> Option<spirv::Word> {
238 for ty in &self.module.types_global_values {
239 if ty.is_type_identical(inst) {
240 if let Some(id) = ty.result_id {
241 return Some(id);
242 }
243 }
244 }
245
246 None
247 }
248
249 pub fn find_return_block_indices(&self) -> Vec<usize> {
251 let mut result = vec![];
252
253 if let Some(sel_fn) = self.selected_function {
254 let func = &self.module.functions[sel_fn];
255
256 for (idx, blk) in func.blocks.iter().enumerate() {
257 let last_instr = blk.instructions.last().unwrap();
259
260 match last_instr.class.opcode {
261 spirv::Op::Return | spirv::Op::ReturnValue => {
262 result.push(idx);
263 }
264 _ => {}
265 }
266 }
267 }
268
269 result
270 }
271
272 pub fn select_function_by_name(&mut self, name: &str) -> BuildResult<()> {
274 for dbg in &self.module.debug_names {
275 if dbg.class.opcode == spirv::Op::Name {
276 if let dr::Operand::IdRef(target_id) = dbg.operands[0] {
277 if let dr::Operand::LiteralString(found_name) = &dbg.operands[1] {
278 if found_name == name {
279 for (idx, func) in self.module.functions.iter().enumerate() {
280 if func.def.as_ref().unwrap().result_id.unwrap() == target_id {
281 return self.select_function(Some(idx));
282 }
283 }
284 }
285 }
286 }
287 }
288 }
289
290 Err(Error::FunctionNotFound)
291 }
292
293 pub fn select_function(&mut self, idx: Option<usize>) -> BuildResult<()> {
295 match idx {
296 Some(idx) => {
297 if idx < self.module.functions.len() {
298 self.selected_function = Some(idx);
299 Ok(())
300 } else {
301 Err(Error::FunctionNotFound)
302 }
303 }
304 None => {
305 self.selected_block = None;
307 self.selected_function = None;
308 Ok(())
309 }
310 }
311 }
312
313 pub fn select_block(&mut self, idx: Option<usize>) -> BuildResult<()> {
315 match idx {
316 Some(idx) => {
317 let selected_function = match self.selected_function {
318 Some(f) => f,
319 None => return Err(Error::DetachedBlock),
320 };
321 if idx < self.module.functions[selected_function].blocks.len() {
322 self.selected_block = Some(idx);
323 Ok(())
324 } else {
325 Err(Error::BlockNotFound)
326 }
327 }
328 None => {
329 self.selected_block = None;
330 Ok(())
331 }
332 }
333 }
334
335 pub fn begin_function(
341 &mut self,
342 return_type: spirv::Word,
343 function_id: Option<spirv::Word>,
344 control: spirv::FunctionControl,
345 function_type: spirv::Word,
346 ) -> BuildResult<spirv::Word> {
347 if self.selected_function.is_some() {
348 return Err(Error::NestedFunction);
349 }
350
351 let id = match function_id {
352 Some(v) => v,
353 None => self.id(),
354 };
355
356 let mut f = dr::Function::new();
357 f.def = Some(dr::Instruction::new(
358 spirv::Op::Function,
359 Some(return_type),
360 Some(id),
361 vec![
362 dr::Operand::FunctionControl(control),
363 dr::Operand::IdRef(function_type),
364 ],
365 ));
366 self.module.functions.push(f);
367 self.selected_function = Some(self.module.functions.len() - 1);
368 Ok(id)
369 }
370
371 pub fn end_function(&mut self) -> BuildResult<()> {
373 let selected_function = match self.selected_function {
374 Some(f) => f,
375 None => return Err(Error::MismatchedFunctionEnd),
376 };
377
378 self.module.functions[selected_function].end = Some(dr::Instruction::new(
379 spirv::Op::FunctionEnd,
380 None,
381 None,
382 vec![],
383 ));
384 self.selected_function = None;
385 Ok(())
386 }
387
388 pub fn function_parameter(&mut self, result_type: spirv::Word) -> BuildResult<spirv::Word> {
390 let selected_function = match self.selected_function {
391 Some(f) => f,
392 None => return Err(Error::DetachedFunctionParameter),
393 };
394 let id = self.id();
395 let inst = dr::Instruction::new(
396 spirv::Op::FunctionParameter,
397 Some(result_type),
398 Some(id),
399 vec![],
400 );
401 self.module.functions[selected_function]
402 .parameters
403 .push(inst);
404 Ok(id)
405 }
406
407 pub fn begin_block(&mut self, label_id: Option<spirv::Word>) -> BuildResult<spirv::Word> {
413 let selected_function = match self.selected_function {
414 Some(f) => f,
415 None => return Err(Error::DetachedBlock),
416 };
417 if self.selected_block.is_some() {
418 return Err(Error::NestedBlock);
419 }
420
421 let id = match label_id {
422 Some(v) => v,
423 None => self.id(),
424 };
425
426 let mut bb = dr::Block::new();
427 bb.label = Some(dr::Instruction::new(
428 spirv::Op::Label,
429 None,
430 Some(id),
431 vec![],
432 ));
433
434 let blocks = &mut self.module.functions[selected_function].blocks;
435 blocks.push(bb);
436 self.selected_block = Some(blocks.len() - 1);
437 Ok(id)
438 }
439
440 pub fn begin_block_no_label(
445 &mut self,
446 label_id: Option<spirv::Word>,
447 ) -> BuildResult<spirv::Word> {
448 let selected_function = match self.selected_function {
449 Some(f) => f,
450 None => return Err(Error::DetachedBlock),
451 };
452 if self.selected_block.is_some() {
453 return Err(Error::NestedBlock);
454 }
455
456 let id = match label_id {
457 Some(v) => v,
458 None => self.id(),
459 };
460
461 let bb = dr::Block::new();
462 let blocks = &mut self.module.functions[selected_function].blocks;
463 blocks.push(bb);
464 self.selected_block = Some(blocks.len() - 1);
465 Ok(id)
466 }
467
468 fn end_block(&mut self, inst: dr::Instruction) -> BuildResult<()> {
469 self.insert_end_block(InsertPoint::End, inst)
470 }
471
472 fn insert_end_block(
473 &mut self,
474 insert_point: InsertPoint,
475 inst: dr::Instruction,
476 ) -> BuildResult<()> {
477 if self.selected_block.is_some() {
478 self.insert_into_block(insert_point, inst)?;
479 self.selected_block = None;
480 return Ok(());
481 }
482
483 Err(Error::MismatchedTerminator)
484 }
485
486 pub fn capability(&mut self, capability: spirv::Capability) {
488 let inst = dr::Instruction::new(
489 spirv::Op::Capability,
490 None,
491 None,
492 vec![dr::Operand::Capability(capability)],
493 );
494 self.module.capabilities.push(inst);
495 }
496
497 pub fn extension(&mut self, extension: impl Into<String>) {
499 let inst = dr::Instruction::new(
500 spirv::Op::Extension,
501 None,
502 None,
503 vec![dr::Operand::LiteralString(extension.into())],
504 );
505 self.module.extensions.push(inst);
506 }
507
508 pub fn ext_inst_import(&mut self, extended_inst_set: impl Into<String>) -> spirv::Word {
510 let id = self.id();
511 let inst = dr::Instruction::new(
512 spirv::Op::ExtInstImport,
513 None,
514 Some(id),
515 vec![dr::Operand::LiteralString(extended_inst_set.into())],
516 );
517 self.module.ext_inst_imports.push(inst);
518 id
519 }
520
521 pub fn memory_model(
523 &mut self,
524 addressing_model: spirv::AddressingModel,
525 memory_model: spirv::MemoryModel,
526 ) {
527 let inst = dr::Instruction::new(
528 spirv::Op::MemoryModel,
529 None,
530 None,
531 vec![
532 dr::Operand::AddressingModel(addressing_model),
533 dr::Operand::MemoryModel(memory_model),
534 ],
535 );
536 self.module.memory_model = Some(inst);
537 }
538
539 pub fn entry_point(
541 &mut self,
542 execution_model: spirv::ExecutionModel,
543 entry_point: spirv::Word,
544 name: impl Into<String>,
545 interface: impl AsRef<[spirv::Word]>,
546 ) {
547 let mut operands = vec![
548 dr::Operand::ExecutionModel(execution_model),
549 dr::Operand::IdRef(entry_point),
550 dr::Operand::LiteralString(name.into()),
551 ];
552 for v in interface.as_ref() {
553 operands.push(dr::Operand::IdRef(*v));
554 }
555
556 let inst = dr::Instruction::new(spirv::Op::EntryPoint, None, None, operands);
557 self.module.entry_points.push(inst);
558 }
559
560 pub fn execution_mode(
562 &mut self,
563 entry_point: spirv::Word,
564 execution_mode: spirv::ExecutionMode,
565 params: impl AsRef<[u32]>,
566 ) {
567 let mut operands = vec![
568 dr::Operand::IdRef(entry_point),
569 dr::Operand::ExecutionMode(execution_mode),
570 ];
571 for v in params.as_ref() {
572 operands.push(dr::Operand::LiteralBit32(*v));
573 }
574
575 let inst = dr::Instruction::new(spirv::Op::ExecutionMode, None, None, operands);
576 self.module.execution_modes.push(inst);
577 }
578
579 pub fn execution_mode_id(
581 &mut self,
582 entry_point: spirv::Word,
583 execution_mode: spirv::ExecutionMode,
584 params: impl AsRef<[u32]>,
585 ) {
586 let mut operands = vec![
587 dr::Operand::IdRef(entry_point),
588 dr::Operand::ExecutionMode(execution_mode),
589 ];
590 for v in params.as_ref() {
591 operands.push(dr::Operand::LiteralBit32(*v));
592 }
593
594 let inst = dr::Instruction::new(spirv::Op::ExecutionModeId, None, None, operands);
595 self.module.execution_modes.push(inst);
596 }
597
598 pub fn ext_inst(
599 &mut self,
600 result_type: spirv::Word,
601 result_id: Option<spirv::Word>,
602 extension_set: spirv::Word,
603 instruction: spirv::Word,
604 operands: impl IntoIterator<Item = dr::Operand>,
605 ) -> BuildResult<spirv::Word> {
606 let mut ops = vec![
607 dr::Operand::IdRef(extension_set),
608 dr::Operand::LiteralExtInstInteger(instruction),
609 ];
610 ops.extend(operands);
611 let _id = result_id.unwrap_or_else(|| self.id());
612 let inst = dr::Instruction::new(spirv::Op::ExtInst, Some(result_type), Some(_id), ops);
613 self.insert_into_block(InsertPoint::End, inst)?;
614 Ok(_id)
615 }
616
617 pub fn line(&mut self, file: spirv::Word, line: u32, column: u32) {
622 let inst = dr::Instruction::new(
623 spirv::Op::Line,
624 None,
625 None,
626 vec![
627 dr::Operand::IdRef(file),
628 dr::Operand::LiteralBit32(line),
629 dr::Operand::LiteralBit32(column),
630 ],
631 );
632 if self.selected_block.is_some() {
633 self.insert_into_block(InsertPoint::End, inst)
634 .expect("Internal error: insert_into_block failed when selected_block was Some");
635 } else {
636 self.module.types_global_values.push(inst);
639 }
640 }
641
642 pub fn no_line(&mut self) {
647 let inst = dr::Instruction::new(spirv::Op::NoLine, None, None, vec![]);
648 if self.selected_block.is_some() {
649 self.insert_into_block(InsertPoint::End, inst)
650 .expect("Internal error: insert_into_block failed when selected_block was Some");
651 } else {
652 self.module.types_global_values.push(inst);
655 }
656 }
657}
658
659include!("autogen_type.rs");
660include!("autogen_constant.rs");
661include!("autogen_annotation.rs");
662include!("autogen_terminator.rs");
663include!("autogen_debug.rs");
664
665impl Builder {
666 pub fn decoration_group(&mut self) -> spirv::Word {
668 let id = self.id();
669 self.module.annotations.push(dr::Instruction::new(
670 spirv::Op::DecorationGroup,
671 None,
672 Some(id),
673 vec![],
674 ));
675 id
676 }
677
678 pub fn string(&mut self, s: impl Into<String>) -> spirv::Word {
679 let id = self.id();
680 self.module.debug_string_source.push(dr::Instruction::new(
681 spirv::Op::String,
682 None,
683 Some(id),
684 vec![dr::Operand::LiteralString(s.into())],
685 ));
686 id
687 }
688}
689
690impl Builder {
691 pub fn type_forward_pointer(
693 &mut self,
694 pointer_type: spirv::Word,
695 storage_class: spirv::StorageClass,
696 ) {
697 self.module.types_global_values.push(dr::Instruction::new(
698 spirv::Op::TypeForwardPointer,
699 None,
700 None,
701 vec![
702 dr::Operand::IdRef(pointer_type),
703 dr::Operand::StorageClass(storage_class),
704 ],
705 ));
706 }
707
708 pub fn type_pointer(
710 &mut self,
711 result_id: Option<spirv::Word>,
712 storage_class: spirv::StorageClass,
713 pointee_type: spirv::Word,
714 ) -> spirv::Word {
715 let mut inst = dr::Instruction::new(
716 spirv::Op::TypePointer,
717 None,
718 result_id,
719 vec![
720 dr::Operand::StorageClass(storage_class),
721 dr::Operand::IdRef(pointee_type),
722 ],
723 );
724 if let Some(result_id) = result_id {
725 self.module.types_global_values.push(inst);
727 result_id
728 } else if let Some(id) = self.dedup_insert_type(&inst) {
729 id
731 } else {
732 let new_id = self.id();
734 inst.result_id = Some(new_id);
735 self.module.types_global_values.push(inst);
736 new_id
737 }
738 }
739
740 pub fn type_opaque(&mut self, type_name: impl Into<String>) -> spirv::Word {
742 let id = self.id();
743 self.module.types_global_values.push(dr::Instruction::new(
744 spirv::Op::TypeOpaque,
745 None,
746 Some(id),
747 vec![dr::Operand::LiteralString(type_name.into())],
748 ));
749 id
750 }
751
752 pub fn constant_bit32(&mut self, result_type: spirv::Word, value: u32) -> spirv::Word {
755 let id = self.id();
756 let inst = dr::Instruction::new(
757 spirv::Op::Constant,
758 Some(result_type),
759 Some(id),
760 vec![dr::Operand::LiteralBit32(value)],
761 );
762 self.module.types_global_values.push(inst);
763 id
764 }
765
766 pub fn constant_bit64(&mut self, result_type: spirv::Word, value: u64) -> spirv::Word {
768 let id = self.id();
769 let inst = dr::Instruction::new(
770 spirv::Op::Constant,
771 Some(result_type),
772 Some(id),
773 vec![dr::Operand::LiteralBit64(value)],
774 );
775 self.module.types_global_values.push(inst);
776 id
777 }
778
779 pub fn spec_constant_bit32(&mut self, result_type: spirv::Word, value: u32) -> spirv::Word {
782 let id = self.id();
783 let inst = dr::Instruction::new(
784 spirv::Op::SpecConstant,
785 Some(result_type),
786 Some(id),
787 vec![dr::Operand::LiteralBit32(value)],
788 );
789 self.module.types_global_values.push(inst);
790 id
791 }
792
793 pub fn spec_constant_bit64(&mut self, result_type: spirv::Word, value: u64) -> spirv::Word {
795 let id = self.id();
796 let inst = dr::Instruction::new(
797 spirv::Op::SpecConstant,
798 Some(result_type),
799 Some(id),
800 vec![dr::Operand::LiteralBit64(value)],
801 );
802 self.module.types_global_values.push(inst);
803 id
804 }
805
806 pub fn variable(
809 &mut self,
810 result_type: spirv::Word,
811 result_id: Option<spirv::Word>,
812 storage_class: spirv::StorageClass,
813 initializer: Option<spirv::Word>,
814 ) -> spirv::Word {
815 let id = match result_id {
816 Some(v) => v,
817 None => self.id(),
818 };
819 let mut operands = vec![dr::Operand::StorageClass(storage_class)];
820 if let Some(val) = initializer {
821 operands.push(dr::Operand::IdRef(val));
822 }
823 let inst = dr::Instruction::new(spirv::Op::Variable, Some(result_type), Some(id), operands);
824
825 match (self.selected_function, self.selected_block) {
826 (Some(selected_function), Some(selected_block)) => {
827 self.module.functions[selected_function].blocks[selected_block]
828 .instructions
829 .push(inst)
830 }
831 _ => self.module.types_global_values.push(inst),
832 }
833 id
834 }
835
836 pub fn undef(
839 &mut self,
840 result_type: spirv::Word,
841 result_id: Option<spirv::Word>,
842 ) -> spirv::Word {
843 let id = match result_id {
844 Some(v) => v,
845 None => self.id(),
846 };
847 let inst = dr::Instruction::new(spirv::Op::Undef, Some(result_type), Some(id), vec![]);
848
849 match (self.selected_function, self.selected_block) {
850 (Some(selected_function), Some(selected_block)) => {
851 self.module.functions[selected_function].blocks[selected_block]
852 .instructions
853 .push(inst)
854 }
855 _ => self.module.types_global_values.push(inst),
856 }
857 id
858 }
859}
860
861include!("autogen_norm_insts.rs");
862
863#[cfg(test)]
864mod tests {
865 use crate::dr;
866 use crate::spirv;
867
868 use super::Builder;
869 use std::f32;
870
871 use crate::binary::Disassemble;
872
873 fn has_only_one_global_inst(module: &dr::Module) -> bool {
874 if !module.functions.is_empty() {
875 return false;
876 }
877 (module.capabilities.len()
878 + module.extensions.len()
879 + module.ext_inst_imports.len()
880 + module.entry_points.len()
881 + module.types_global_values.len()
882 + module.execution_modes.len()
883 + module.debug_string_source.len()
884 + module.debug_names.len()
885 + module.debug_module_processed.len()
886 + module.annotations.len())
887 + (usize::from(module.memory_model.is_some()))
888 == 1
889 }
890
891 #[test]
892 fn test_spirv_version() {
893 let mut b = Builder::new();
894 b.set_version(1, 2);
895 let m = b.module();
896 let header = &m.header;
897 assert!(header.is_some());
898 assert_eq!((1, 2), header.as_ref().unwrap().version());
899 }
900
901 #[test]
902 fn test_memory_model() {
903 let mut b = Builder::new();
904 b.memory_model(spirv::AddressingModel::Logical, spirv::MemoryModel::Simple);
905 let m = b.module();
906 assert!(m.memory_model.is_some());
907 let inst = m.memory_model.as_ref().unwrap();
908 assert!(has_only_one_global_inst(&m));
909 assert_eq!("MemoryModel", inst.class.opname);
910 assert_eq!(2, inst.operands.len());
911 assert_eq!(
912 dr::Operand::from(spirv::AddressingModel::Logical),
913 inst.operands[0]
914 );
915 assert_eq!(
916 dr::Operand::from(spirv::MemoryModel::Simple),
917 inst.operands[1]
918 );
919 }
920
921 #[test]
922 fn test_decoration_no_additional_params() {
923 let mut b = Builder::new();
924 b.member_decorate(1, 0, spirv::Decoration::RelaxedPrecision, vec![]);
925 let m = b.module();
926 assert!(has_only_one_global_inst(&m));
927 let inst = m.annotations.last().unwrap();
928 assert_eq!("MemberDecorate", inst.class.opname);
929 assert_eq!(3, inst.operands.len());
930 assert_eq!(dr::Operand::IdRef(1), inst.operands[0]);
931 assert_eq!(dr::Operand::from(0u32), inst.operands[1]);
932 assert_eq!(
933 dr::Operand::from(spirv::Decoration::RelaxedPrecision),
934 inst.operands[2]
935 );
936 }
937
938 #[test]
939 fn test_decoration_with_additional_params() {
940 let mut b = Builder::new();
941 b.decorate(
942 1,
943 spirv::Decoration::LinkageAttributes,
944 vec![
945 dr::Operand::from("name"),
946 dr::Operand::from(spirv::LinkageType::Export),
947 ],
948 );
949 let m = b.module();
950 assert!(has_only_one_global_inst(&m));
951 let inst = m.annotations.last().unwrap();
952 assert_eq!("Decorate", inst.class.opname);
953 assert_eq!(4, inst.operands.len());
954 assert_eq!(dr::Operand::IdRef(1), inst.operands[0]);
955 assert_eq!(
956 dr::Operand::from(spirv::Decoration::LinkageAttributes),
957 inst.operands[1]
958 );
959 assert_eq!(dr::Operand::from("name"), inst.operands[2]);
960 assert_eq!(
961 dr::Operand::from(spirv::LinkageType::Export),
962 inst.operands[3]
963 );
964 }
965
966 #[test]
967 fn test_constant_bit32() {
968 let mut b = Builder::new();
969 let float = b.type_float(32);
970 b.constant_bit32(float, f32::consts::PI.to_bits());
972 b.constant_bit32(float, 2e-10f32.to_bits());
973 b.constant_bit32(float, 0.0f32.to_bits());
975 b.constant_bit32(float, f32::NEG_INFINITY.to_bits());
977 b.constant_bit32(float, (-1.0e-40f32).to_bits());
979 b.constant_bit32(float, f32::NAN.to_bits());
981 let m = b.module();
982 assert_eq!(7, m.types_global_values.len());
983
984 let inst = &m.types_global_values[1];
985 assert_eq!(spirv::Op::Constant, inst.class.opcode);
986 assert_eq!(Some(1), inst.result_type);
987 assert_eq!(Some(2), inst.result_id);
988 assert_eq!(
989 dr::Operand::from(f32::consts::PI.to_bits()),
990 inst.operands[0]
991 );
992
993 let inst = &m.types_global_values[2];
994 assert_eq!(spirv::Op::Constant, inst.class.opcode);
995 assert_eq!(Some(1), inst.result_type);
996 assert_eq!(Some(3), inst.result_id);
997 assert_eq!(dr::Operand::from(2e-10f32.to_bits()), inst.operands[0]);
998
999 let inst = &m.types_global_values[3];
1000 assert_eq!(spirv::Op::Constant, inst.class.opcode);
1001 assert_eq!(Some(1), inst.result_type);
1002 assert_eq!(Some(4), inst.result_id);
1003 assert_eq!(dr::Operand::from(0.0f32.to_bits()), inst.operands[0]);
1004
1005 let inst = &m.types_global_values[4];
1006 assert_eq!(spirv::Op::Constant, inst.class.opcode);
1007 assert_eq!(Some(1), inst.result_type);
1008 assert_eq!(Some(5), inst.result_id);
1009 assert_eq!(
1010 dr::Operand::from(f32::NEG_INFINITY.to_bits()),
1011 inst.operands[0]
1012 );
1013
1014 let inst = &m.types_global_values[5];
1015 assert_eq!(spirv::Op::Constant, inst.class.opcode);
1016 assert_eq!(Some(1), inst.result_type);
1017 assert_eq!(Some(6), inst.result_id);
1018 assert_eq!(dr::Operand::from((-1.0e-40f32).to_bits()), inst.operands[0]);
1019
1020 let inst = &m.types_global_values[6];
1021 assert_eq!(spirv::Op::Constant, inst.class.opcode);
1022 assert_eq!(Some(1), inst.result_type);
1023 assert_eq!(Some(7), inst.result_id);
1024 match inst.operands[0] {
1026 dr::Operand::LiteralBit32(f) => assert!(f32::from_bits(f).is_nan()),
1027 _ => panic!(),
1028 }
1029 }
1030
1031 #[test]
1032 fn test_spec_constant_bit32() {
1033 let mut b = Builder::new();
1034 let float = b.type_float(32);
1035 b.spec_constant_bit32(float, 10.0f32.to_bits());
1037 b.spec_constant_bit32(float, (-0.0f32).to_bits());
1039 b.spec_constant_bit32(float, f32::INFINITY.to_bits());
1041 b.spec_constant_bit32(float, 1.0e-40f32.to_bits());
1043 b.spec_constant_bit32(float, f32::NAN.to_bits());
1045 let m = b.module();
1046 assert_eq!(6, m.types_global_values.len());
1047
1048 let inst = &m.types_global_values[1];
1049 assert_eq!(spirv::Op::SpecConstant, inst.class.opcode);
1050 assert_eq!(Some(1), inst.result_type);
1051 assert_eq!(Some(2), inst.result_id);
1052 assert_eq!(dr::Operand::from(10.0f32.to_bits()), inst.operands[0]);
1053
1054 let inst = &m.types_global_values[2];
1055 assert_eq!(spirv::Op::SpecConstant, inst.class.opcode);
1056 assert_eq!(Some(1), inst.result_type);
1057 assert_eq!(Some(3), inst.result_id);
1058 assert_eq!(dr::Operand::from((-0.0f32).to_bits()), inst.operands[0]);
1059
1060 let inst = &m.types_global_values[3];
1061 assert_eq!(spirv::Op::SpecConstant, inst.class.opcode);
1062 assert_eq!(Some(1), inst.result_type);
1063 assert_eq!(Some(4), inst.result_id);
1064 assert_eq!(dr::Operand::from(f32::INFINITY.to_bits()), inst.operands[0]);
1065
1066 let inst = &m.types_global_values[4];
1067 assert_eq!(spirv::Op::SpecConstant, inst.class.opcode);
1068 assert_eq!(Some(1), inst.result_type);
1069 assert_eq!(Some(5), inst.result_id);
1070 assert_eq!(dr::Operand::from(1.0e-40f32.to_bits()), inst.operands[0]);
1071
1072 let inst = &m.types_global_values[5];
1073 assert_eq!(spirv::Op::SpecConstant, inst.class.opcode);
1074 assert_eq!(Some(1), inst.result_type);
1075 assert_eq!(Some(6), inst.result_id);
1076 match inst.operands[0] {
1078 dr::Operand::LiteralBit32(f) => assert!(f32::from_bits(f).is_nan()),
1079 _ => panic!(),
1080 }
1081 }
1082
1083 #[test]
1084 fn test_forward_ref_pointer_type() {
1085 let mut b = Builder::new();
1086 let float = b.type_float(32); let p1 = b.type_pointer(None, spirv::StorageClass::Input, float); let pointee = b.id(); b.type_forward_pointer(pointee, spirv::StorageClass::Output);
1092 let p2 = b.type_pointer(Some(pointee), spirv::StorageClass::Output, float);
1093 let m = b.module();
1094 assert_eq!(1, float);
1095 assert_eq!(2, p1);
1096 assert_eq!(pointee, p2); assert_eq!(4, m.types_global_values.len());
1098
1099 let inst = &m.types_global_values[0];
1100 assert_eq!(spirv::Op::TypeFloat, inst.class.opcode);
1101 assert_eq!(None, inst.result_type);
1102 assert_eq!(Some(1), inst.result_id);
1103 assert_eq!(vec![dr::Operand::LiteralBit32(32)], inst.operands);
1104
1105 let inst = &m.types_global_values[1];
1106 assert_eq!(spirv::Op::TypePointer, inst.class.opcode);
1107 assert_eq!(None, inst.result_type);
1108 assert_eq!(Some(2), inst.result_id);
1109 assert_eq!(
1110 vec![
1111 dr::Operand::from(spirv::StorageClass::Input),
1112 dr::Operand::IdRef(1),
1113 ],
1114 inst.operands
1115 );
1116
1117 let inst = &m.types_global_values[2];
1118 assert_eq!(spirv::Op::TypeForwardPointer, inst.class.opcode);
1119 assert_eq!(None, inst.result_type);
1120 assert_eq!(None, inst.result_id);
1121 assert_eq!(
1122 vec![
1123 dr::Operand::IdRef(3),
1124 dr::Operand::from(spirv::StorageClass::Output),
1125 ],
1126 inst.operands
1127 );
1128
1129 let inst = &m.types_global_values[3];
1130 assert_eq!(spirv::Op::TypePointer, inst.class.opcode);
1131 assert_eq!(None, inst.result_type);
1132 assert_eq!(Some(3), inst.result_id);
1133 assert_eq!(
1134 vec![
1135 dr::Operand::from(spirv::StorageClass::Output),
1136 dr::Operand::IdRef(1),
1137 ],
1138 inst.operands
1139 );
1140 }
1141
1142 #[test]
1143 fn test_forward_ref_phi() {
1144 let mut b = Builder::new();
1145
1146 let float = b.type_float(32);
1147 assert_eq!(1, float);
1148 let f32ff32 = b.type_function(float, vec![float]);
1149 assert_eq!(2, f32ff32);
1150 let c0 = b.constant_bit32(float, 0.0f32.to_bits());
1151 assert_eq!(3, c0);
1152
1153 let fid = b
1154 .begin_function(float, None, spirv::FunctionControl::NONE, f32ff32)
1155 .unwrap();
1156 assert_eq!(4, fid);
1157
1158 let epid = b.begin_block(None).unwrap(); assert_eq!(5, epid);
1160 let target1 = b.id();
1161 assert_eq!(6, target1);
1162 assert!(b.branch(target1).is_ok());
1163
1164 let pbid = b.begin_block(Some(target1)).unwrap(); assert_eq!(target1, pbid);
1166 let target2 = b.id();
1167 assert_eq!(7, target2);
1168 let fr_add = b.id();
1169 assert_eq!(8, fr_add);
1170 let phi = b
1172 .phi(
1173 float,
1174 None,
1175 vec![(c0, epid), (fr_add, pbid), (c0, target2)],
1177 )
1178 .unwrap();
1179 assert_eq!(9, phi);
1180 let res_add = b.f_add(float, Some(fr_add), c0, c0).unwrap();
1181 assert_eq!(res_add, fr_add);
1182 assert!(b.branch(target2).is_ok());
1183
1184 let exid = b.begin_block(Some(target2)).unwrap(); assert_eq!(exid, target2);
1186 assert!(b.ret_value(c0).is_ok());
1187
1188 assert!(b.end_function().is_ok());
1189
1190 let m = b.module();
1191 assert_eq!(1, m.functions.len());
1192 assert_eq!(
1193 m.functions.first().unwrap().disassemble(),
1194 "%4 = OpFunction %1 None %2\n\
1195 %5 = OpLabel\n\
1196 OpBranch %6\n\
1197 %6 = OpLabel\n\
1198 %9 = OpPhi %1 %3 %5 %8 %6 %3 %7\n\
1199 %8 = OpFAdd %1 %3 %3\n\
1200 OpBranch %7\n\
1201 %7 = OpLabel\n\
1202 OpReturnValue %3\n\
1203 OpFunctionEnd"
1204 );
1205 }
1206
1207 #[test]
1208 fn test_build_variables() {
1209 let mut b = Builder::new();
1210
1211 let void = b.type_void();
1212 assert_eq!(1, void);
1213 let float = b.type_float(32);
1214 assert_eq!(2, float);
1215 let ifp = b.type_pointer(None, spirv::StorageClass::Input, float);
1216 assert_eq!(3, ifp);
1217 let ffp = b.type_pointer(None, spirv::StorageClass::Function, float);
1218 assert_eq!(4, ffp);
1219 let voidfvoid = b.type_function(void, vec![void]);
1220 assert_eq!(5, voidfvoid);
1221
1222 let v1 = b.variable(ifp, None, spirv::StorageClass::Input, None);
1224 assert_eq!(6, v1);
1225
1226 let f = b
1227 .begin_function(void, None, spirv::FunctionControl::NONE, voidfvoid)
1228 .unwrap();
1229 assert_eq!(7, f);
1230 let bb = b.begin_block(None).unwrap();
1231 assert_eq!(8, bb);
1232 let v2 = b.variable(ffp, None, spirv::StorageClass::Function, None);
1234 assert_eq!(9, v2);
1235 assert!(b.ret().is_ok());
1236 assert!(b.end_function().is_ok());
1237
1238 let v3 = b.variable(ifp, None, spirv::StorageClass::Input, None);
1240 assert_eq!(10, v3);
1241
1242 assert_eq!(
1243 b.module().disassemble(),
1244 "; SPIR-V\n; Version: 1.6\n; Generator: rspirv\n; Bound: 11\n\
1245 %1 = OpTypeVoid\n\
1246 %2 = OpTypeFloat 32\n\
1247 %3 = OpTypePointer Input %2\n\
1248 %4 = OpTypePointer Function %2\n\
1249 %5 = OpTypeFunction %1 %1\n\
1250 %6 = OpVariable %3 Input\n\
1251 %10 = OpVariable %3 Input\n\
1252 %7 = OpFunction %1 None %5\n\
1253 %8 = OpLabel\n\
1254 %9 = OpVariable %4 Function\n\
1255 OpReturn\n\
1256 OpFunctionEnd"
1257 );
1258 }
1259
1260 #[test]
1261 fn test_build_undefs() {
1262 let mut b = Builder::new();
1263
1264 let void = b.type_void();
1265 assert_eq!(1, void);
1266 let float = b.type_float(32);
1267 assert_eq!(2, float);
1268 let voidfvoid = b.type_function(void, vec![void]);
1269 assert_eq!(3, voidfvoid);
1270
1271 let v1 = b.undef(float, None);
1273 assert_eq!(4, v1);
1274
1275 let f = b
1276 .begin_function(void, None, spirv::FunctionControl::NONE, voidfvoid)
1277 .unwrap();
1278 assert_eq!(5, f);
1279 let bb = b.begin_block(None).unwrap();
1280 assert_eq!(6, bb);
1281 let v2 = b.undef(float, None);
1283 assert_eq!(7, v2);
1284 assert!(b.ret().is_ok());
1285 assert!(b.end_function().is_ok());
1286
1287 let v3 = b.undef(float, None);
1289 assert_eq!(8, v3);
1290
1291 assert_eq!(
1292 b.module().disassemble(),
1293 "; SPIR-V\n; Version: 1.6\n; Generator: rspirv\n; Bound: 9\n\
1294 %1 = OpTypeVoid\n\
1295 %2 = OpTypeFloat 32\n\
1296 %3 = OpTypeFunction %1 %1\n\
1297 %4 = OpUndef %2\n\
1298 %8 = OpUndef %2\n\
1299 %5 = OpFunction %1 None %3\n\
1300 %6 = OpLabel\n\
1301 %7 = OpUndef %2\n\
1302 OpReturn\n\
1303 OpFunctionEnd"
1304 );
1305 }
1306}