1use anyhow::Result;
2use spirv::{MAJOR_VERSION, MINOR_VERSION};
3use std::{convert::TryInto, iter::FromIterator};
4
5use super::Instrs;
6
7#[derive(Debug, Clone)]
8pub struct SpirvHeader {
9 pub magic: u32,
10 pub version: u32,
11 pub generator: u32,
12 pub bound: u32,
13 pub schema: u32,
14}
15impl Default for SpirvHeader {
16 fn default() -> Self {
17 SpirvHeader {
18 magic: 0x07230203,
19 version: ((MAJOR_VERSION as u32) << 16) | ((MINOR_VERSION as u32) << 8),
20 generator: 0,
21 bound: 0,
22 schema: 0,
23 }
24 }
25}
26impl SpirvHeader {
27 pub fn new(version: u32, generator: u32) -> Self {
28 SpirvHeader {
29 version,
30 generator,
31 ..Default::default()
32 }
33 }
34 pub fn words(&self) -> [u32; 5] {
35 [
36 self.magic,
37 self.version,
38 self.generator,
39 self.bound,
40 self.schema,
41 ]
42 }
43}
44
45#[derive(Debug, Default, Clone)]
47pub struct SpirvBinary(Vec<u32>);
48impl From<Vec<u32>> for SpirvBinary {
49 fn from(x: Vec<u32>) -> Self {
50 SpirvBinary(x)
51 }
52}
53impl From<&[u32]> for SpirvBinary {
54 fn from(x: &[u32]) -> Self {
55 SpirvBinary(x.to_owned())
56 }
57}
58impl FromIterator<u32> for SpirvBinary {
59 fn from_iter<I: IntoIterator<Item = u32>>(iter: I) -> Self {
60 SpirvBinary(iter.into_iter().collect::<Vec<u32>>())
61 }
62}
63impl From<&[u8]> for SpirvBinary {
64 fn from(x: &[u8]) -> Self {
65 if x.len() == 0 {
66 return SpirvBinary::default();
67 }
68 x.chunks_exact(4)
69 .map(|x| x.try_into().unwrap())
70 .map(match x[0] {
71 0x03 => u32::from_le_bytes,
72 0x07 => u32::from_be_bytes,
73 _ => return SpirvBinary::default(),
74 })
75 .collect::<SpirvBinary>()
76 }
77}
78impl From<Vec<u8>> for SpirvBinary {
79 fn from(x: Vec<u8>) -> Self {
80 SpirvBinary::from(x.as_ref() as &[u8])
81 }
82}
83
84impl SpirvBinary {
85 pub fn words(&self) -> &[u32] {
86 &self.0
87 }
88 pub fn into_words(self) -> Vec<u32> {
89 self.0
90 }
91 pub fn into_bytes(self) -> Vec<u8> {
92 self.0
93 .iter()
94 .flat_map(|x| x.to_le_bytes().to_vec())
95 .collect::<Vec<u8>>()
96 }
97
98 pub fn instrs(&self) -> Result<Instrs> {
99 const HEADER_LEN: usize = 5;
100 Instrs::new(&self.words()[HEADER_LEN..])
101 }
102
103 pub fn header(&self) -> Option<SpirvHeader> {
104 let header = &self.words()[..5];
105 if header.len() < 5 {
106 return None;
107 }
108 Some(SpirvHeader {
109 magic: header[0],
110 version: header[1],
111 generator: header[2],
112 bound: header[3],
113 schema: header[4],
114 })
115 }
116}