Skip to main content

nox_spirv/op/
common.rs

1//! SPIR-V common types
2use core::{
3    fmt::{self, Display, Debug},
4    slice,
5};
6use crate::{
7    core::*,
8    stream::*,
9    module::*,
10};
11use super::*;
12/// Reference to an id representing the result's type of the enclosing instruction.
13#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
14pub struct IdResultType(pub(crate) u32);
15impl Display for IdResultType {
16
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        write!(f, "%{}", self.0)
19    }
20}
21impl Word for IdResultType {
22
23    #[inline]
24    fn from_word(word: u32) -> Self {
25        Self(word)
26    }
27}
28/// Reference to an id representing the result's type of the enclosing instruction.
29#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
30pub struct IdResult(pub(crate) u32);
31impl Display for IdResult {
32
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        write!(f, "%{}", self.0)
35    }
36}
37impl Word for IdResult {
38
39    #[inline]
40    fn from_word(word: u32) -> Self {
41        Self(word)
42    }
43}
44/// Reference to an id representing a 32-bit integer that is a mask from the MemorySemantics
45/// operand kind.
46#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
47pub struct IdMemorySemantics(pub(crate) u32);
48impl Display for IdMemorySemantics {
49
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        write!(f, "%{}", self.0)
52    }
53}
54impl Word for IdMemorySemantics {
55
56    #[inline]
57    fn from_word(word: u32) -> Self {
58        Self(word)
59    }
60}
61/// Reference to an id representing a 32-bit integer that is a mask from the Scope operand kind.
62#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
63pub struct IdScope(pub(crate) u32);
64impl Display for IdScope {
65
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "%{}", self.0)
68    }
69}
70impl Word for IdScope {
71
72    #[inline]
73    fn from_word(word: u32) -> Self {
74        Self(word)
75    }
76}
77/// Reference to an id.
78#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
79pub struct IdRef(pub(crate) u32);
80impl Display for IdRef {
81
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        write!(f, "%{}", self.0)
84    }
85}
86impl Word for IdRef {
87
88    #[inline]
89    fn from_word(word: u32) -> Self {
90        Self(word)
91    }
92}
93impl From<IdResultType> for IdRef {
94
95    #[inline]
96    fn from(value: IdResultType) -> Self {
97        Self(value.0)
98    }
99}
100impl From<IdResult> for IdRef {
101
102    #[inline]
103    fn from(value: IdResult) -> Self {
104        Self(value.0)
105    }
106}
107/// An integer consuming one or more words.
108pub type LiteralInteger = u32;
109/// A null-terminated stream of characters consuming an integral number of words.
110pub type LiteralString<'a> = CompilerStr<'a>;
111/// A float consuming one word.
112pub type LiteralFloat = f32;
113impl Word for LiteralFloat {
114
115    #[inline]
116    fn from_word(word: u32) -> Self {
117        Self::from_bits(word)
118    }
119}
120/// A literal number whose size and format are determined by a previous operand in the enclosing
121/// instruction.
122pub type LiteralContextDependentNumber = Literal;
123impl<'a> LiteralContextDependentNumber {
124
125    pub fn parse_one(
126        module: &Module<'a>,
127        stream: &mut InstructionStream<'a>,
128        ctx: &mut ParseContext,
129    ) -> ParseResult<Self> {
130        let Some(result_type) = ctx.result_type else {
131            return Err(ParseError::ExpectedContextResultType)
132        };
133        let mut ty_stream = module
134            .get_result(result_type.into())
135            .ok_or(ParseError::InvalidIdResult(result_type.into()))?;
136        match ty_stream.code() {
137            Code::TYPE_INT => {
138                ty_stream.advance(1)?;
139                let width = ty_stream.read()?;
140                let signedness = ty_stream.read()?;
141                Ok(if signedness == 1 {
142                    match width {
143                        8 => Literal::I8(u8::cast_signed(
144                            stream.read()? as u8
145                        )),
146                        16 => Literal::I16(u16::cast_signed(
147                            stream.read()? as u16,
148                        )),
149                        32 => Literal::I32(u32::cast_signed(
150                            stream.read()?,
151                        )),
152                        64 => Literal::I64(u64::cast_signed(
153                            stream.read()? as u64 |
154                            ((stream.read()? as u64) << 32)
155                        )),
156                        x => return Err(ParseError
157                            ::InvalidIntLiteralWidth(x)
158                        )
159                    }
160                } else {
161                    match width {
162                        8 => Literal::U8(stream.read()? as u8),
163                        16 => Literal::U16(stream.read()? as u16),
164                        32 => Literal::U32(stream.read()?),
165                        64 => Literal::U64(
166                            stream.read()? as u64 |
167                            ((stream.read()? as u64) << 32)
168                        ),
169                        x => return Err(ParseError
170                            ::InvalidIntLiteralWidth(x)
171                        )
172                    }
173                })
174            },
175            Code::TYPE_FLOAT => {
176                ty_stream.advance(1)?;
177                let width = ty_stream.read()?;
178                Ok(match width {
179                    16 => Literal::F16(stream.read()? as u16),
180                    32 => Literal::F32(f32::from_bits(stream.read()?)),
181                    64 => Literal::F64(f64::from_bits(
182                        stream.read()? as u64 |
183                        ((stream.read()? as u64) << 32)
184                    )),
185                    x => return Err(ParseError
186                        ::InvalidFloatLiteralWidth(x)
187                    )
188                })
189            },
190            x => Err(ParseError::InvalidType {
191                expected: "float or int type",
192                found: x,
193            })
194        }
195    }
196}
197/// A 32-bit unsigned integer indicating which instruction to use and determining the layout
198/// of following operands (for OpExtInst).
199pub type LiteralExtInstInteger = u32;
200/// An opcode indicating the operation to be performed and determining the layout of following
201/// operands (for OpSpecConstantOp).
202#[derive(Clone, Copy, Debug)]
203pub struct LiteralSpecConstantOpInteger<'a> {
204    pub code: Code,
205    pub operands: &'a [IdRef],
206}
207impl<'a> LiteralSpecConstantOpInteger<'a> {
208
209    pub fn parse_one(
210        stream: &mut InstructionStream<'a>,
211    ) -> ParseResult<Self>
212    {
213        Ok(Self {
214            code: Code::from_word(stream.read()?),
215            operands: IdRef::parse_eos(stream)?,
216        })
217    }
218}
219impl<'a> Display for LiteralSpecConstantOpInteger<'a> {
220
221    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222        write!(f, "{}", self.code)?;
223        for operand in self.operands {
224            write!(f, " {operand}")?;
225        }
226        Ok(())
227    }
228}
229#[repr(C)]
230#[derive(Clone, Copy, Debug)]
231pub struct Pair<T, U>(T, U)
232    where
233        T: Word + Debug + Display,
234        U: Word + Debug + Display;
235impl<T, U> Display for Pair<T, U>
236    where
237        T: Word + Debug + Display,
238        U: Word + Debug + Display,
239{
240
241    #[inline]
242    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243        write!(f, "{} {}", self.0, self.1)
244    }
245}
246impl<'a, T, U> Pair<T, U>
247    where
248        T: Word + Debug + Display,
249        U: Word + Debug + Display,
250{
251
252    #[inline]
253    pub fn parse_one(
254        stream: &mut InstructionStream<'a>,
255    ) -> ParseResult<Self> {
256        Ok(Self(T::from_word(stream.read()?), U::from_word(stream.read()?)))
257    }
258
259    #[inline]
260    pub fn parse_eos(
261        stream: &mut InstructionStream<'a>,
262    ) -> ParseResult<&'a [Self]> {
263        let words = stream.read_words(None)?;
264        if !words.len().is_multiple_of(2) {
265            return Err(ParseError::InvalidPairWordCount(words.len() as u32))
266        }
267        unsafe {
268            Ok(slice::from_raw_parts(
269                words.as_ptr().cast(),
270                words.len() / 2
271            ))
272        }
273    }
274}
275pub type PairLiteralIntegerIdRef = Pair<LiteralInteger, IdRef>;
276pub type PairIdRefLiteralInteger = Pair<IdRef, LiteralInteger>;
277pub type PairIdRefIdRef = Pair<IdRef, IdRef>;
278#[derive(Default, Clone, Copy)]
279pub struct InstInfo {
280    pub name: &'static str,
281    pub has_id_result_type: bool,
282    pub has_id_result: bool,
283}