use super::{Instruction, LogicalLayout, PhysicalLayout}; use spirv::{Op, Word, MAGIC_NUMBER}; use std::iter; // https://github.com/KhronosGroup/SPIRV-Headers/pull/195 const GENERATOR: Word = 28; impl PhysicalLayout { pub(super) const fn new(version: Word) -> Self { PhysicalLayout { magic_number: MAGIC_NUMBER, version, generator: GENERATOR, bound: 0, instruction_schema: 0x0u32, } } pub(super) fn in_words(&self, sink: &mut impl Extend) { sink.extend(iter::once(self.magic_number)); sink.extend(iter::once(self.version)); sink.extend(iter::once(self.generator)); sink.extend(iter::once(self.bound)); sink.extend(iter::once(self.instruction_schema)); } } impl super::recyclable::Recyclable for PhysicalLayout { fn recycle(self) -> Self { PhysicalLayout { magic_number: self.magic_number, version: self.version, generator: self.generator, instruction_schema: self.instruction_schema, bound: 0, } } } impl LogicalLayout { pub(super) fn in_words(&self, sink: &mut impl Extend) { sink.extend(self.capabilities.iter().cloned()); sink.extend(self.extensions.iter().cloned()); sink.extend(self.ext_inst_imports.iter().cloned()); sink.extend(self.memory_model.iter().cloned()); sink.extend(self.entry_points.iter().cloned()); sink.extend(self.execution_modes.iter().cloned()); sink.extend(self.debugs.iter().cloned()); sink.extend(self.annotations.iter().cloned()); sink.extend(self.declarations.iter().cloned()); sink.extend(self.function_declarations.iter().cloned()); sink.extend(self.function_definitions.iter().cloned()); } } impl super::recyclable::Recyclable for LogicalLayout { fn recycle(self) -> Self { Self { capabilities: self.capabilities.recycle(), extensions: self.extensions.recycle(), ext_inst_imports: self.ext_inst_imports.recycle(), memory_model: self.memory_model.recycle(), entry_points: self.entry_points.recycle(), execution_modes: self.execution_modes.recycle(), debugs: self.debugs.recycle(), annotations: self.annotations.recycle(), declarations: self.declarations.recycle(), function_declarations: self.function_declarations.recycle(), function_definitions: self.function_definitions.recycle(), } } } impl Instruction { pub(super) const fn new(op: Op) -> Self { Instruction { op, wc: 1, // Always start at 1 for the first word (OP + WC), type_id: None, result_id: None, operands: vec![], } } #[allow(clippy::panic)] pub(super) fn set_type(&mut self, id: Word) { assert!(self.type_id.is_none(), "Type can only be set once"); self.type_id = Some(id); self.wc += 1; } #[allow(clippy::panic)] pub(super) fn set_result(&mut self, id: Word) { assert!(self.result_id.is_none(), "Result can only be set once"); self.result_id = Some(id); self.wc += 1; } pub(super) fn add_operand(&mut self, operand: Word) { self.operands.push(operand); self.wc += 1; } pub(super) fn add_operands(&mut self, operands: Vec) { for operand in operands.into_iter() { self.add_operand(operand) } } pub(super) fn to_words(&self, sink: &mut impl Extend) { sink.extend(Some(self.wc << 16 | self.op as u32)); sink.extend(self.type_id); sink.extend(self.result_id); sink.extend(self.operands.iter().cloned()); } } impl Instruction { #[cfg(test)] fn validate(&self, words: &[Word]) { let mut inst_index = 0; let (wc, op) = ((words[inst_index] >> 16) as u16, words[inst_index] as u16); inst_index += 1; assert_eq!(wc, words.len() as u16); assert_eq!(op, self.op as u16); if self.type_id.is_some() { assert_eq!(words[inst_index], self.type_id.unwrap()); inst_index += 1; } if self.result_id.is_some() { assert_eq!(words[inst_index], self.result_id.unwrap()); inst_index += 1; } for (op_index, i) in (inst_index..wc as usize).enumerate() { assert_eq!(words[i], self.operands[op_index]); } } } #[test] fn test_physical_layout_in_words() { let bound = 5; let version = 0x10203; let mut output = vec![]; let mut layout = PhysicalLayout::new(version); layout.bound = bound; layout.in_words(&mut output); assert_eq!(&output, &[MAGIC_NUMBER, version, GENERATOR, bound, 0,]); } #[test] fn test_logical_layout_in_words() { let mut output = vec![]; let mut layout = LogicalLayout::default(); let layout_vectors = 11; let mut instructions = Vec::with_capacity(layout_vectors); let vector_names = &[ "Capabilities", "Extensions", "External Instruction Imports", "Memory Model", "Entry Points", "Execution Modes", "Debugs", "Annotations", "Declarations", "Function Declarations", "Function Definitions", ]; for (i, _) in vector_names.iter().enumerate().take(layout_vectors) { let mut dummy_instruction = Instruction::new(Op::Constant); dummy_instruction.set_type((i + 1) as u32); dummy_instruction.set_result((i + 2) as u32); dummy_instruction.add_operand((i + 3) as u32); dummy_instruction.add_operands(super::helpers::string_to_words( format!("This is the vector: {}", vector_names[i]).as_str(), )); instructions.push(dummy_instruction); } instructions[0].to_words(&mut layout.capabilities); instructions[1].to_words(&mut layout.extensions); instructions[2].to_words(&mut layout.ext_inst_imports); instructions[3].to_words(&mut layout.memory_model); instructions[4].to_words(&mut layout.entry_points); instructions[5].to_words(&mut layout.execution_modes); instructions[6].to_words(&mut layout.debugs); instructions[7].to_words(&mut layout.annotations); instructions[8].to_words(&mut layout.declarations); instructions[9].to_words(&mut layout.function_declarations); instructions[10].to_words(&mut layout.function_definitions); layout.in_words(&mut output); let mut index: usize = 0; for instruction in instructions { let wc = instruction.wc as usize; instruction.validate(&output[index..index + wc]); index += wc; } }