1use alloc::{vec, vec::Vec};
2use core::iter;
3
4use spirv::{Op, Word, MAGIC_NUMBER};
5
6use super::{Instruction, LogicalLayout, PhysicalLayout};
7
8#[cfg(test)]
9use alloc::format;
10
11const GENERATOR: Word = 28;
13
14impl PhysicalLayout {
15 pub(super) const fn new(version: Word) -> Self {
16 PhysicalLayout {
17 magic_number: MAGIC_NUMBER,
18 version,
19 generator: GENERATOR,
20 bound: 0,
21 instruction_schema: 0x0u32,
22 }
23 }
24
25 pub(super) fn in_words(&self, sink: &mut impl Extend<Word>) {
26 sink.extend(iter::once(self.magic_number));
27 sink.extend(iter::once(self.version));
28 sink.extend(iter::once(self.generator));
29 sink.extend(iter::once(self.bound));
30 sink.extend(iter::once(self.instruction_schema));
31 }
32}
33
34impl super::recyclable::Recyclable for PhysicalLayout {
35 fn recycle(self) -> Self {
36 PhysicalLayout {
37 magic_number: self.magic_number,
38 version: self.version,
39 generator: self.generator,
40 instruction_schema: self.instruction_schema,
41 bound: 0,
42 }
43 }
44}
45
46impl LogicalLayout {
47 pub(super) fn in_words(&self, sink: &mut impl Extend<Word>) {
48 sink.extend(self.capabilities.iter().cloned());
49 sink.extend(self.extensions.iter().cloned());
50 sink.extend(self.ext_inst_imports.iter().cloned());
51 sink.extend(self.memory_model.iter().cloned());
52 sink.extend(self.entry_points.iter().cloned());
53 sink.extend(self.execution_modes.iter().cloned());
54 sink.extend(self.debugs.iter().cloned());
55 sink.extend(self.annotations.iter().cloned());
56 sink.extend(self.declarations.iter().cloned());
57 sink.extend(self.function_declarations.iter().cloned());
58 sink.extend(self.function_definitions.iter().cloned());
59 }
60}
61
62impl super::recyclable::Recyclable for LogicalLayout {
63 fn recycle(self) -> Self {
64 Self {
65 capabilities: self.capabilities.recycle(),
66 extensions: self.extensions.recycle(),
67 ext_inst_imports: self.ext_inst_imports.recycle(),
68 memory_model: self.memory_model.recycle(),
69 entry_points: self.entry_points.recycle(),
70 execution_modes: self.execution_modes.recycle(),
71 debugs: self.debugs.recycle(),
72 annotations: self.annotations.recycle(),
73 declarations: self.declarations.recycle(),
74 function_declarations: self.function_declarations.recycle(),
75 function_definitions: self.function_definitions.recycle(),
76 }
77 }
78}
79
80impl Instruction {
81 pub(super) const fn new(op: Op) -> Self {
82 Instruction {
83 op,
84 wc: 1, type_id: None,
86 result_id: None,
87 operands: vec![],
88 }
89 }
90
91 #[allow(clippy::panic)]
92 pub(super) fn set_type(&mut self, id: Word) {
93 assert!(self.type_id.is_none(), "Type can only be set once");
94 self.type_id = Some(id);
95 self.wc += 1;
96 }
97
98 #[allow(clippy::panic)]
99 pub(super) fn set_result(&mut self, id: Word) {
100 assert!(self.result_id.is_none(), "Result can only be set once");
101 self.result_id = Some(id);
102 self.wc += 1;
103 }
104
105 pub(super) fn add_operand(&mut self, operand: Word) {
106 self.operands.push(operand);
107 self.wc += 1;
108 }
109
110 pub(super) fn add_operands(&mut self, operands: Vec<Word>) {
111 for operand in operands.into_iter() {
112 self.add_operand(operand)
113 }
114 }
115
116 pub(super) fn to_words(&self, sink: &mut impl Extend<Word>) {
117 sink.extend(Some((self.wc << 16) | self.op as u32));
118 sink.extend(self.type_id);
119 sink.extend(self.result_id);
120 sink.extend(self.operands.iter().cloned());
121 }
122}
123
124impl Instruction {
125 #[cfg(test)]
126 fn validate(&self, words: &[Word]) {
127 let mut inst_index = 0;
128 let (wc, op) = ((words[inst_index] >> 16) as u16, words[inst_index] as u16);
129 inst_index += 1;
130
131 assert_eq!(wc, words.len() as u16);
132 assert_eq!(op, self.op as u16);
133
134 if self.type_id.is_some() {
135 assert_eq!(words[inst_index], self.type_id.unwrap());
136 inst_index += 1;
137 }
138
139 if self.result_id.is_some() {
140 assert_eq!(words[inst_index], self.result_id.unwrap());
141 inst_index += 1;
142 }
143
144 for (op_index, i) in (inst_index..wc as usize).enumerate() {
145 assert_eq!(words[i], self.operands[op_index]);
146 }
147 }
148}
149
150#[test]
151fn test_physical_layout_in_words() {
152 let bound = 5;
153 let version = 0x10203;
154
155 let mut output = vec![];
156 let mut layout = PhysicalLayout::new(version);
157 layout.bound = bound;
158
159 layout.in_words(&mut output);
160
161 assert_eq!(&output, &[MAGIC_NUMBER, version, GENERATOR, bound, 0,]);
162}
163
164#[test]
165fn test_logical_layout_in_words() {
166 let mut output = vec![];
167 let mut layout = LogicalLayout::default();
168 let layout_vectors = 11;
169 let mut instructions = Vec::with_capacity(layout_vectors);
170
171 let vector_names = &[
172 "Capabilities",
173 "Extensions",
174 "External Instruction Imports",
175 "Memory Model",
176 "Entry Points",
177 "Execution Modes",
178 "Debugs",
179 "Annotations",
180 "Declarations",
181 "Function Declarations",
182 "Function Definitions",
183 ];
184
185 for (i, _) in vector_names.iter().enumerate().take(layout_vectors) {
186 let mut dummy_instruction = Instruction::new(Op::Constant);
187 dummy_instruction.set_type((i + 1) as u32);
188 dummy_instruction.set_result((i + 2) as u32);
189 dummy_instruction.add_operand((i + 3) as u32);
190 dummy_instruction.add_operands(super::helpers::string_to_words(
191 format!("This is the vector: {}", vector_names[i]).as_str(),
192 ));
193 instructions.push(dummy_instruction);
194 }
195
196 instructions[0].to_words(&mut layout.capabilities);
197 instructions[1].to_words(&mut layout.extensions);
198 instructions[2].to_words(&mut layout.ext_inst_imports);
199 instructions[3].to_words(&mut layout.memory_model);
200 instructions[4].to_words(&mut layout.entry_points);
201 instructions[5].to_words(&mut layout.execution_modes);
202 instructions[6].to_words(&mut layout.debugs);
203 instructions[7].to_words(&mut layout.annotations);
204 instructions[8].to_words(&mut layout.declarations);
205 instructions[9].to_words(&mut layout.function_declarations);
206 instructions[10].to_words(&mut layout.function_definitions);
207
208 layout.in_words(&mut output);
209
210 let mut index: usize = 0;
211 for instruction in instructions {
212 let wc = instruction.wc as usize;
213 instruction.validate(&output[index..index + wc]);
214 index += wc;
215 }
216}