1use crate::grammar;
2use crate::spirv;
3
4use crate::spirv::Word;
5use crate::utils::version;
6use std::{convert, fmt};
7
8#[derive(Clone, Debug, Default)]
17pub struct Module {
18 pub header: Option<ModuleHeader>,
20 pub capabilities: Vec<Instruction>,
22 pub extensions: Vec<Instruction>,
24 pub ext_inst_imports: Vec<Instruction>,
26 pub memory_model: Option<Instruction>,
31 pub entry_points: Vec<Instruction>,
33 pub execution_modes: Vec<Instruction>,
35 pub debug_string_source: Vec<Instruction>,
37 pub debug_names: Vec<Instruction>,
39 pub debug_module_processed: Vec<Instruction>,
41 pub annotations: Vec<Instruction>,
43 pub types_global_values: Vec<Instruction>,
48 pub functions: Vec<Function>,
50}
51
52#[derive(Clone, Debug, PartialEq, Eq)]
54pub struct ModuleHeader {
55 pub magic_number: Word,
56 pub version: Word,
57 pub generator: Word,
58 pub bound: Word,
59 pub reserved_word: Word,
60}
61
62#[derive(Clone, Debug, Default)]
64pub struct Function {
65 pub def: Option<Instruction>,
67 pub end: Option<Instruction>,
69 pub parameters: Vec<Instruction>,
71 pub blocks: Vec<Block>,
73}
74
75#[derive(Clone, Debug, Default)]
77pub struct Block {
78 pub label: Option<Instruction>,
80 pub instructions: Vec<Instruction>,
82}
83
84#[derive(Clone, Debug, PartialEq, Eq, Hash)]
86pub struct Instruction {
87 pub class: &'static grammar::Instruction<'static>,
89 pub result_type: Option<Word>,
91 pub result_id: Option<Word>,
93 pub operands: Vec<Operand>,
95}
96
97impl Instruction {
98 pub fn is_type_identical(&self, other: &Instruction) -> bool {
100 self.class.opcode == other.class.opcode && self.operands == other.operands
101 }
102}
103
104include!("autogen_operand.rs");
105
106impl Module {
107 pub fn new() -> Self {
109 Module {
110 header: None,
111 capabilities: vec![],
112 extensions: vec![],
113 ext_inst_imports: vec![],
114 memory_model: None,
115 entry_points: vec![],
116 execution_modes: vec![],
117 debug_string_source: vec![],
118 debug_names: vec![],
119 debug_module_processed: vec![],
120 annotations: vec![],
121 types_global_values: vec![],
122 functions: vec![],
123 }
124 }
125
126 pub fn global_inst_iter(&self) -> impl Iterator<Item = &Instruction> {
128 self.capabilities
129 .iter()
130 .chain(&self.extensions)
131 .chain(&self.ext_inst_imports)
132 .chain(&self.memory_model)
133 .chain(&self.entry_points)
134 .chain(&self.execution_modes)
135 .chain(&self.debug_string_source)
136 .chain(&self.debug_names)
137 .chain(&self.debug_module_processed)
138 .chain(&self.annotations)
139 .chain(&self.types_global_values)
140 }
141
142 pub fn global_inst_iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction> {
144 self.capabilities
145 .iter_mut()
146 .chain(&mut self.extensions)
147 .chain(&mut self.ext_inst_imports)
148 .chain(&mut self.memory_model)
149 .chain(&mut self.entry_points)
150 .chain(&mut self.execution_modes)
151 .chain(&mut self.debug_string_source)
152 .chain(&mut self.debug_names)
153 .chain(&mut self.debug_module_processed)
154 .chain(&mut self.annotations)
155 .chain(&mut self.types_global_values)
156 }
157
158 pub fn all_inst_iter(&self) -> impl Iterator<Item = &Instruction> {
160 self.capabilities
161 .iter()
162 .chain(&self.extensions)
163 .chain(&self.ext_inst_imports)
164 .chain(&self.memory_model)
165 .chain(&self.entry_points)
166 .chain(&self.execution_modes)
167 .chain(&self.debug_string_source)
168 .chain(&self.debug_names)
169 .chain(&self.debug_module_processed)
170 .chain(&self.annotations)
171 .chain(&self.types_global_values)
172 .chain(self.functions.iter().flat_map(|f| f.all_inst_iter()))
173 }
174
175 pub fn all_inst_iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction> {
177 self.capabilities
178 .iter_mut()
179 .chain(&mut self.extensions)
180 .chain(&mut self.ext_inst_imports)
181 .chain(&mut self.memory_model)
182 .chain(&mut self.entry_points)
183 .chain(&mut self.execution_modes)
184 .chain(&mut self.debug_string_source)
185 .chain(&mut self.debug_names)
186 .chain(&mut self.debug_module_processed)
187 .chain(&mut self.annotations)
188 .chain(&mut self.types_global_values)
189 .chain(
190 self.functions
191 .iter_mut()
192 .flat_map(|f| f.all_inst_iter_mut()),
193 )
194 }
195}
196
197impl ModuleHeader {
198 pub fn new(bound: Word) -> ModuleHeader {
200 ModuleHeader {
201 magic_number: spirv::MAGIC_NUMBER,
202 version: version::create_word_from_version(spirv::MAJOR_VERSION, spirv::MINOR_VERSION),
203 generator: 0x000f_0000, bound,
205 reserved_word: 0,
206 }
207 }
208
209 pub fn set_version(&mut self, major: u8, minor: u8) {
211 self.version = version::create_word_from_version(major, minor);
212 }
213
214 pub fn version(&self) -> (u8, u8) {
216 version::create_version_from_word(self.version)
217 }
218
219 pub fn generator(&self) -> (&str, u16) {
221 let tool = (self.generator & 0xffff_0000) >> 16;
222 let version = (self.generator & 0xffff) as u16;
223 let tool: &str = match tool {
224 0 => "The Khronos Group",
225 1 => "LunarG",
226 2 => "Valve",
227 3 => "Codeplay",
228 4 => "NVIDIA",
229 5 => "ARM",
230 6 => "LLVM/SPIR-V Translator",
231 7 => "SPIR-V Tools Assembler",
232 8 => "Glslang",
233 9 => "Qualcomm",
234 10 => "AMD",
235 11 => "Intel",
236 12 => "Imagination",
237 13 => "Shaderc",
238 14 => "spiregg",
239 15 => "rspirv",
240 _ => "Unknown",
241 };
242 (tool, version)
243 }
244}
245
246impl Function {
247 pub fn new() -> Self {
249 Function {
250 def: None,
251 end: None,
252 parameters: vec![],
253 blocks: vec![],
254 }
255 }
256
257 pub fn def_id(&self) -> Option<Word> {
258 self.def.as_ref().and_then(|inst| inst.result_id)
259 }
260
261 pub fn all_inst_iter(&self) -> impl Iterator<Item = &Instruction> {
262 self.def
263 .iter()
264 .chain(self.parameters.iter())
265 .chain(
266 self.blocks
267 .iter()
268 .flat_map(|b| b.label.iter().chain(b.instructions.iter())),
269 )
270 .chain(self.end.iter())
271 }
272
273 pub fn all_inst_iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction> {
274 self.def
275 .iter_mut()
276 .chain(self.parameters.iter_mut())
277 .chain(
278 self.blocks
279 .iter_mut()
280 .flat_map(|b| b.label.iter_mut().chain(b.instructions.iter_mut())),
281 )
282 .chain(self.end.iter_mut())
283 }
284}
285
286impl Block {
287 pub fn new() -> Self {
289 Block {
290 label: None,
291 instructions: vec![],
292 }
293 }
294
295 pub fn label_id(&self) -> Option<Word> {
296 self.label.as_ref().and_then(|inst| inst.result_id)
297 }
298}
299
300impl Instruction {
301 pub fn new(
303 opcode: spirv::Op,
304 result_type: Option<Word>,
305 result_id: Option<Word>,
306 operands: Vec<Operand>,
307 ) -> Self {
308 Instruction {
309 class: grammar::CoreInstructionTable::get(opcode),
310 result_type,
311 result_id,
312 operands,
313 }
314 }
315}
316
317impl<'a> convert::From<&'a str> for Operand {
319 fn from(val: &'a str) -> Self {
320 Operand::LiteralString(val.to_owned())
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use crate::dr;
327 use crate::spirv;
328
329 #[test]
330 fn test_convert_from_string() {
331 assert_eq!(
332 dr::Operand::LiteralString("wow".to_string()),
333 dr::Operand::from("wow")
334 );
335 assert_eq!(
336 dr::Operand::LiteralString("wow".to_string()),
337 dr::Operand::from("wow".to_string())
338 );
339 }
340
341 #[test]
342 fn test_convert_from_numbers() {
343 assert_eq!(dr::Operand::LiteralBit32(16u32), dr::Operand::from(16u32));
344 assert_eq!(
345 dr::Operand::LiteralBit64(128934u64),
346 dr::Operand::from(128934u64)
347 );
348 assert_eq!(
349 dr::Operand::LiteralBit32(std::f32::consts::PI.to_bits()),
350 dr::Operand::from(std::f32::consts::PI.to_bits())
351 );
352 assert_eq!(
353 dr::Operand::LiteralBit64(10.4235f64.to_bits()),
354 dr::Operand::from(10.4235f64.to_bits())
355 );
356 }
357
358 #[test]
359 fn test_convert_from_bit_enums() {
360 assert_eq!(
361 dr::Operand::LoopControl(spirv::LoopControl::DONT_UNROLL | spirv::LoopControl::UNROLL),
362 dr::Operand::from(spirv::LoopControl::DONT_UNROLL | spirv::LoopControl::UNROLL)
363 );
364 assert_eq!(
365 dr::Operand::MemoryAccess(spirv::MemoryAccess::NONE),
366 dr::Operand::from(spirv::MemoryAccess::NONE)
367 );
368 }
369
370 #[test]
371 fn test_convert_from_value_enums() {
372 assert_eq!(
373 dr::Operand::BuiltIn(spirv::BuiltIn::Position),
374 dr::Operand::from(spirv::BuiltIn::Position)
375 );
376 assert_eq!(
377 dr::Operand::Capability(spirv::Capability::Pipes),
378 dr::Operand::from(spirv::Capability::Pipes)
379 );
380 }
381
382 #[test]
383 fn test_convert_from_op() {
384 assert_eq!(
385 dr::Operand::LiteralSpecConstantOpInteger(spirv::Op::IAdd),
386 dr::Operand::from(spirv::Op::IAdd)
387 );
388 }
389
390 #[test]
391 fn test_operand_display() {
392 assert_eq!(
393 format!(
394 "{}",
395 dr::Operand::FunctionControl(
396 spirv::FunctionControl::INLINE | spirv::FunctionControl::CONST
397 )
398 ),
399 "FunctionControl(INLINE | CONST)",
400 );
401 assert_eq!(format!("{}", dr::Operand::IdRef(3)), "%3");
402 assert_eq!(format!("{}", dr::Operand::LiteralBit32(3)), "3");
403 }
404}