spirv_utils/
lib.rs

1// Copyright 2016 James Miller
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::io::Read;
10use std::path::Path;
11
12pub mod desc;
13pub mod instruction;
14pub mod parse;
15
16use desc::Id;
17use instruction::Instruction;
18use parse::Result;
19
20/**
21 * Minimal representation of a SPIR-V module.
22 */
23pub struct RawModule {
24    instructions: Vec<Instruction>,
25    def_map: Box<[usize]>,
26    use_map: Box<[Vec<usize>]>
27}
28
29impl RawModule {
30
31    /**
32     * Load a module from a file
33     */
34    pub fn load_module<P: AsRef<Path>>(path: P) -> Result<RawModule> {
35        let file = try!(std::fs::File::open(path));
36
37        RawModule::read_module(file)
38    }
39
40    /**
41     * Read a module
42     */
43    pub fn read_module<R: Read>(reader: R) -> Result<RawModule> {
44        let mut reader = try!(parse::Reader::new(reader));
45
46        let header = try!(reader.read_header());
47
48        let ids = header.id_bound as usize;
49        let mut def_map = (vec![!0; ids]).into_boxed_slice();
50        let mut use_map = (vec![Vec::new(); ids]).into_boxed_slice();
51
52        let mut instructions = Vec::with_capacity(ids);
53
54        while let Some(raw_inst) = try!(reader.read_instruction()) {
55            let inst = try!(parse::parse_raw_instruction(raw_inst));
56            let inst_idx = instructions.len();
57
58            if let Some(id) = inst.defines_value() {
59                let idx = id.0 as usize;
60                def_map[idx] = inst_idx;
61            } else if let Some(id) = inst.defines_type() {
62                let idx = id.0 as usize;
63                def_map[idx] = inst_idx;
64            }
65
66            let uses = inst.uses();
67            for id in uses {
68                let idx = id.0 as usize;
69                if idx == 0 { continue; }
70                use_map[idx].push(inst_idx);
71            }
72
73            instructions.push(inst);
74        }
75
76        Ok(RawModule {
77            instructions: instructions,
78            def_map: def_map,
79            use_map: use_map
80        })
81    }
82
83    /**
84     * Gets the instructions in the module
85     */
86    pub fn instructions<'a>(&'a self) -> &'a [Instruction] {
87        &self.instructions[..]
88    }
89
90    /**
91     * Gets the index of the instruction that defines the given id, if
92     * any
93     */
94    pub fn def_index<I: Into<Id>>(&self, id: I) -> Option<usize> {
95        let idx = id.into().0 as usize;
96        if idx == 0 { return None; }
97
98        self.def_map.get(idx).and_then(|&idx| {
99            if idx == !0 {
100                None
101            } else {
102                Some(idx)
103            }
104        })
105    }
106
107    /**
108     * Gets the indices of the instructions that use the given id
109     */
110    pub fn use_indices<'a, I: Into<Id>>(&'a self, id: I) -> Option<&'a [usize]> {
111        let idx = id.into().0 as usize;
112        if idx == 0 { return None; }
113
114        self.use_map.get(idx).map(|indices| {
115            &indices[..]
116        })
117    }
118
119    /**
120     * Gets the instruction that defines the given Id, if any
121     */
122    pub fn def<'a, I: Into<Id>>(&'a self, id: I) -> Option<&'a Instruction> {
123        self.def_index(id).map(|idx| {
124            &self.instructions[idx]
125        })
126    }
127
128    /**
129     * Returns an iterator over the uses of the given Id
130     */
131    pub fn uses<'a, I: Into<Id>>(&'a self, id: I) -> Uses<'a> {
132        let indices = self.use_indices(id).unwrap_or(&[]);
133
134        Uses {
135            instructions: self.instructions(),
136            indices: indices
137        }
138    }
139}
140
141pub struct Uses<'a> {
142    instructions: &'a [Instruction],
143    indices: &'a [usize],
144}
145
146impl<'a> Iterator for Uses<'a> {
147    type Item = &'a Instruction;
148
149    fn next(&mut self) -> Option<&'a Instruction> {
150        if self.indices.len() == 0 {
151            return None;
152        }
153
154        let idx = self.indices[0];
155        self.indices = &self.indices[1..];
156
157        self.instructions.get(idx)
158    }
159
160    fn size_hint(&self) -> (usize, Option<usize>) {
161        let len = self.indices.len();
162        (len, Some(len))
163    }
164}