use grammar;
use spirv;
use spirv::Word;
use utils::version;
use std::{convert, fmt, iter};
#[derive(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 debugs: Vec<Instruction>,
pub annotations: Vec<Instruction>,
pub types_global_values: Vec<Instruction>,
pub functions: Vec<Function>,
}
#[derive(Debug, PartialEq)]
pub struct ModuleHeader {
pub magic_number: Word,
pub version: Word,
pub generator: Word,
pub bound: Word,
pub reserved_word: Word,
}
#[derive(Debug, Default)]
pub struct Function {
pub def: Option<Instruction>,
pub end: Option<Instruction>,
pub parameters: Vec<Instruction>,
pub basic_blocks: Vec<BasicBlock>,
}
#[derive(Debug, Default)]
pub struct BasicBlock {
pub label: Option<Instruction>,
pub instructions: Vec<Instruction>,
}
#[derive(Debug)]
pub struct Instruction {
pub class: &'static grammar::Instruction<'static>,
pub result_type: Option<Word>,
pub result_id: Option<Word>,
pub operands: Vec<Operand>,
}
pub struct InstIter<'i> {
instructions: Vec<&'i Instruction>,
index: usize,
}
impl<'i> InstIter<'i> {
pub fn new(insts: Vec<&'i Instruction>) -> InstIter<'i> {
InstIter {
instructions: insts,
index: 0,
}
}
}
impl<'i> iter::Iterator for InstIter<'i> {
type Item = &'i Instruction;
fn next(&mut self) -> Option<&'i Instruction> {
if self.index < self.instructions.len() {
let inst = self.instructions[self.index];
self.index += 1;
Some(inst)
} else {
None
}
}
}
include!("operand.rs");
impl Module {
pub fn new() -> Module {
Module {
header: None,
capabilities: vec![],
extensions: vec![],
ext_inst_imports: vec![],
memory_model: None,
entry_points: vec![],
execution_modes: vec![],
debugs: vec![],
annotations: vec![],
types_global_values: vec![],
functions: vec![],
}
}
pub fn global_inst_iter(&self) -> InstIter {
let mut insts = vec![];
let mut i: Vec<&Instruction> = self.capabilities.iter().collect();
insts.append(&mut i);
let mut i: Vec<&Instruction> = self.extensions.iter().collect();
insts.append(&mut i);
let mut i: Vec<&Instruction> = self.ext_inst_imports.iter().collect();
insts.append(&mut i);
if let Some(ref i) = self.memory_model {
insts.push(i);
}
let mut i: Vec<&Instruction> = self.entry_points.iter().collect();
insts.append(&mut i);
let mut i: Vec<&Instruction> = self.execution_modes.iter().collect();
insts.append(&mut i);
let mut i: Vec<&Instruction> = self.debugs.iter().collect();
insts.append(&mut i);
let mut i: Vec<&Instruction> = self.annotations.iter().collect();
insts.append(&mut i);
let mut i: Vec<&Instruction> = self.types_global_values.iter().collect();
insts.append(&mut i);
InstIter::new(insts)
}
}
impl ModuleHeader {
pub fn new(bound: Word) -> ModuleHeader {
ModuleHeader {
magic_number: spirv::MAGIC_NUMBER,
version: (spirv::MAJOR_VERSION << 16) | (spirv::MINOR_VERSION << 8),
generator: 0x000f0000, bound: bound,
reserved_word: 0,
}
}
pub fn set_version(&mut self, major: u8, minor: u8) {
self.version = ((major as u32) << 16) | ((minor as u32) << 8);
}
pub fn version(&self) -> (u8, u8) {
version::create_version_from_word(self.version)
}
pub fn generator(&self) -> (&str, u16) {
let tool = (self.generator & 0xffff0000) >> 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() -> Function {
Function {
def: None,
end: None,
parameters: vec![],
basic_blocks: vec![],
}
}
}
impl BasicBlock {
pub fn new() -> BasicBlock {
BasicBlock {
label: None,
instructions: vec![],
}
}
}
impl Instruction {
pub fn new(opcode: spirv::Op,
result_type: Option<Word>,
result_id: Option<Word>,
operands: Vec<Operand>)
-> Instruction {
Instruction {
class: grammar::CoreInstructionTable::get(opcode),
result_type: result_type,
result_id: result_id,
operands: operands,
}
}
}
impl<'a> convert::From<&'a str> for Operand {
fn from(val: &'a str) -> Self {
Operand::LiteralString(val.to_owned())
}
}
impl convert::From<u32> for Operand {
fn from(val: u32) -> Self {
Operand::LiteralInt32(val)
}
}
#[cfg(test)]
mod tests {
use mr;
use spirv;
#[test]
fn test_convert_from_string() {
assert_eq!(mr::Operand::LiteralString("wow".to_string()),
mr::Operand::from("wow"));
assert_eq!(mr::Operand::LiteralString("wow".to_string()),
mr::Operand::from("wow".to_string()));
}
#[test]
fn test_convert_from_numbers() {
assert_eq!(mr::Operand::LiteralInt32(16u32), mr::Operand::from(16u32));
assert_eq!(mr::Operand::LiteralInt64(128934u64),
mr::Operand::from(128934u64));
assert_eq!(mr::Operand::LiteralFloat32(3.14f32),
mr::Operand::from(3.14f32));
assert_eq!(mr::Operand::LiteralFloat64(10.4235f64),
mr::Operand::from(10.4235f64));
}
#[test]
fn test_convert_from_bit_enums() {
assert_eq!(mr::Operand::LoopControl(spirv::LoopControl::DONT_UNROLL |
spirv::LoopControl::UNROLL),
mr::Operand::from(spirv::LoopControl::DONT_UNROLL | spirv::LoopControl::UNROLL));
assert_eq!(mr::Operand::MemoryAccess(spirv::MemoryAccess::NONE),
mr::Operand::from(spirv::MemoryAccess::NONE));
}
#[test]
fn test_convert_from_value_enums() {
assert_eq!(mr::Operand::BuiltIn(spirv::BuiltIn::Position),
mr::Operand::from(spirv::BuiltIn::Position));
assert_eq!(mr::Operand::Capability(spirv::Capability::Pipes),
mr::Operand::from(spirv::Capability::Pipes));
}
#[test]
fn test_convert_from_op() {
assert_eq!(mr::Operand::LiteralSpecConstantOpInteger(spirv::Op::IAdd),
mr::Operand::from(spirv::Op::IAdd));
}
}