use crate::grammar;
use crate::spirv;
use crate::spirv::Word;
use crate::utils::version;
use std::{convert, fmt};
#[derive(Clone, Debug, Default)]
pub struct Module {
pub header: Option<ModuleHeader>,
pub capabilities: Vec<Instruction>,
pub extensions: Vec<Instruction>,
pub ext_inst_imports: Vec<Instruction>,
pub memory_model: Option<Instruction>,
pub entry_points: Vec<Instruction>,
pub execution_modes: Vec<Instruction>,
pub debug_string_source: Vec<Instruction>,
pub debug_names: Vec<Instruction>,
pub debug_module_processed: Vec<Instruction>,
pub annotations: Vec<Instruction>,
pub types_global_values: Vec<Instruction>,
pub functions: Vec<Function>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ModuleHeader {
pub magic_number: Word,
pub version: Word,
pub generator: Word,
pub bound: Word,
pub reserved_word: Word,
}
#[derive(Clone, Debug, Default)]
pub struct Function {
pub def: Option<Instruction>,
pub end: Option<Instruction>,
pub parameters: Vec<Instruction>,
pub blocks: Vec<Block>,
}
#[derive(Clone, Debug, Default)]
pub struct Block {
pub label: Option<Instruction>,
pub instructions: Vec<Instruction>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Instruction {
pub class: &'static grammar::Instruction<'static>,
pub result_type: Option<Word>,
pub result_id: Option<Word>,
pub operands: Vec<Operand>,
}
impl Instruction {
pub fn is_type_identical(&self, other: &Instruction) -> bool {
self.class.opcode == other.class.opcode && self.operands == other.operands
}
}
include!("autogen_operand.rs");
impl Module {
pub fn new() -> Self {
Module {
header: None,
capabilities: vec![],
extensions: vec![],
ext_inst_imports: vec![],
memory_model: None,
entry_points: vec![],
execution_modes: vec![],
debug_string_source: vec![],
debug_names: vec![],
debug_module_processed: vec![],
annotations: vec![],
types_global_values: vec![],
functions: vec![],
}
}
pub fn global_inst_iter(&self) -> impl Iterator<Item = &Instruction> {
self.capabilities
.iter()
.chain(&self.extensions)
.chain(&self.ext_inst_imports)
.chain(&self.memory_model)
.chain(&self.entry_points)
.chain(&self.execution_modes)
.chain(&self.debug_string_source)
.chain(&self.debug_names)
.chain(&self.debug_module_processed)
.chain(&self.annotations)
.chain(&self.types_global_values)
}
pub fn global_inst_iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction> {
self.capabilities
.iter_mut()
.chain(&mut self.extensions)
.chain(&mut self.ext_inst_imports)
.chain(&mut self.memory_model)
.chain(&mut self.entry_points)
.chain(&mut self.execution_modes)
.chain(&mut self.debug_string_source)
.chain(&mut self.debug_names)
.chain(&mut self.debug_module_processed)
.chain(&mut self.annotations)
.chain(&mut self.types_global_values)
}
pub fn all_inst_iter(&self) -> impl Iterator<Item = &Instruction> {
self.capabilities
.iter()
.chain(&self.extensions)
.chain(&self.ext_inst_imports)
.chain(&self.memory_model)
.chain(&self.entry_points)
.chain(&self.execution_modes)
.chain(&self.debug_string_source)
.chain(&self.debug_names)
.chain(&self.debug_module_processed)
.chain(&self.annotations)
.chain(&self.types_global_values)
.chain(self.functions.iter().flat_map(|f| f.all_inst_iter()))
}
pub fn all_inst_iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction> {
self.capabilities
.iter_mut()
.chain(&mut self.extensions)
.chain(&mut self.ext_inst_imports)
.chain(&mut self.memory_model)
.chain(&mut self.entry_points)
.chain(&mut self.execution_modes)
.chain(&mut self.debug_string_source)
.chain(&mut self.debug_names)
.chain(&mut self.debug_module_processed)
.chain(&mut self.annotations)
.chain(&mut self.types_global_values)
.chain(
self.functions
.iter_mut()
.flat_map(|f| f.all_inst_iter_mut()),
)
}
}
impl ModuleHeader {
pub fn new(bound: Word) -> ModuleHeader {
ModuleHeader {
magic_number: spirv::MAGIC_NUMBER,
version: version::create_word_from_version(spirv::MAJOR_VERSION, spirv::MINOR_VERSION),
generator: 0x000f_0000, bound,
reserved_word: 0,
}
}
pub fn set_version(&mut self, major: u8, minor: u8) {
self.version = version::create_word_from_version(major, minor);
}
pub fn version(&self) -> (u8, u8) {
version::create_version_from_word(self.version)
}
pub fn generator(&self) -> (&str, u16) {
let tool = (self.generator & 0xffff_0000) >> 16;
let version = (self.generator & 0xffff) as u16;
let tool: &str = match tool {
0 => "The Khronos Group",
1 => "LunarG",
2 => "Valve",
3 => "Codeplay",
4 => "NVIDIA",
5 => "ARM",
6 => "LLVM/SPIR-V Translator",
7 => "SPIR-V Tools Assembler",
8 => "Glslang",
9 => "Qualcomm",
10 => "AMD",
11 => "Intel",
12 => "Imagination",
13 => "Shaderc",
14 => "spiregg",
15 => "rspirv",
_ => "Unknown",
};
(tool, version)
}
}
impl Function {
pub fn new() -> Self {
Function {
def: None,
end: None,
parameters: vec![],
blocks: vec![],
}
}
pub fn def_id(&self) -> Option<Word> {
self.def.as_ref().and_then(|inst| inst.result_id)
}
pub fn all_inst_iter(&self) -> impl Iterator<Item = &Instruction> {
self.def
.iter()
.chain(self.parameters.iter())
.chain(
self.blocks
.iter()
.flat_map(|b| b.label.iter().chain(b.instructions.iter())),
)
.chain(self.end.iter())
}
pub fn all_inst_iter_mut(&mut self) -> impl Iterator<Item = &mut Instruction> {
self.def
.iter_mut()
.chain(self.parameters.iter_mut())
.chain(
self.blocks
.iter_mut()
.flat_map(|b| b.label.iter_mut().chain(b.instructions.iter_mut())),
)
.chain(self.end.iter_mut())
}
}
impl Block {
pub fn new() -> Self {
Block {
label: None,
instructions: vec![],
}
}
pub fn label_id(&self) -> Option<Word> {
self.label.as_ref().and_then(|inst| inst.result_id)
}
}
impl Instruction {
pub fn new(
opcode: spirv::Op,
result_type: Option<Word>,
result_id: Option<Word>,
operands: Vec<Operand>,
) -> Self {
Instruction {
class: grammar::CoreInstructionTable::get(opcode),
result_type,
result_id,
operands,
}
}
}
impl<'a> convert::From<&'a str> for Operand {
fn from(val: &'a str) -> Self {
Operand::LiteralString(val.to_owned())
}
}
#[cfg(test)]
mod tests {
use crate::dr;
use crate::spirv;
#[test]
fn test_convert_from_string() {
assert_eq!(
dr::Operand::LiteralString("wow".to_string()),
dr::Operand::from("wow")
);
assert_eq!(
dr::Operand::LiteralString("wow".to_string()),
dr::Operand::from("wow".to_string())
);
}
#[test]
fn test_convert_from_numbers() {
assert_eq!(dr::Operand::LiteralInt32(16u32), dr::Operand::from(16u32));
assert_eq!(
dr::Operand::LiteralInt64(128934u64),
dr::Operand::from(128934u64)
);
assert_eq!(
dr::Operand::LiteralFloat32(3.14f32),
dr::Operand::from(3.14f32)
);
assert_eq!(
dr::Operand::LiteralFloat64(10.4235f64),
dr::Operand::from(10.4235f64)
);
}
#[test]
fn test_convert_from_bit_enums() {
assert_eq!(
dr::Operand::LoopControl(spirv::LoopControl::DONT_UNROLL | spirv::LoopControl::UNROLL),
dr::Operand::from(spirv::LoopControl::DONT_UNROLL | spirv::LoopControl::UNROLL)
);
assert_eq!(
dr::Operand::MemoryAccess(spirv::MemoryAccess::NONE),
dr::Operand::from(spirv::MemoryAccess::NONE)
);
}
#[test]
fn test_convert_from_value_enums() {
assert_eq!(
dr::Operand::BuiltIn(spirv::BuiltIn::Position),
dr::Operand::from(spirv::BuiltIn::Position)
);
assert_eq!(
dr::Operand::Capability(spirv::Capability::Pipes),
dr::Operand::from(spirv::Capability::Pipes)
);
}
#[test]
fn test_convert_from_op() {
assert_eq!(
dr::Operand::LiteralSpecConstantOpInteger(spirv::Op::IAdd),
dr::Operand::from(spirv::Op::IAdd)
);
}
#[test]
fn test_operand_display() {
assert_eq!(
format!(
"{}",
dr::Operand::FunctionControl(spirv::FunctionControl::INLINE)
),
"INLINE",
);
assert_eq!(format!("{}", dr::Operand::IdRef(3)), "%3");
assert_eq!(format!("{}", dr::Operand::LiteralInt32(3)), "3");
}
}