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                let int = InstTypeInt {
139                    id_result: IdResult::parse_one(&mut ty_stream)?,
140                    width: ty_stream.read()?,
141                    signedness: ty_stream.read()?,
142                };
143                Ok(if int.signedness == 1 {
144                    match int.width {
145                        8 => Literal::I8(u8::cast_signed(
146                            stream.read()? as u8
147                        )),
148                        16 => Literal::I16(u16::cast_signed(
149                            stream.read()? as u16,
150                        )),
151                        32 => Literal::I32(u32::cast_signed(
152                            stream.read()?,
153                        )),
154                        64 => Literal::I64(u64::cast_signed(
155                            stream.read()? as u64 |
156                            ((stream.read()? as u64) << 32)
157                        )),
158                        x => return Err(ParseError
159                            ::InvalidIntLiteralWidth(x)
160                        )
161                    }
162                } else {
163                    match int.width {
164                        8 => Literal::U8(stream.read()? as u8),
165                        16 => Literal::U16(stream.read()? as u16),
166                        32 => Literal::U32(stream.read()?),
167                        64 => Literal::U64(
168                            stream.read()? as u64 |
169                            ((stream.read()? as u64) << 32)
170                        ),
171                        x => return Err(ParseError
172                            ::InvalidIntLiteralWidth(x)
173                        )
174                    }
175                })
176            },
177            Code::TYPE_FLOAT => {
178                let float = InstTypeFloat {
179                    id_result: IdResult::parse_one(&mut ty_stream)?,
180                    width: ty_stream.read()?,
181                    floating_point_encoding: FPEncoding::parse_optional(&mut ty_stream)?,
182                };
183                Ok(match float.width {
184                    16 => Literal::F16(stream.read()? as u16),
185                    32 => Literal::F32(f32::from_bits(stream.read()?)),
186                    64 => Literal::F64(f64::from_bits(
187                        stream.read()? as u64 |
188                        ((stream.read()? as u64) << 32)
189                    )),
190                    x => return Err(ParseError
191                        ::InvalidFloatLiteralWidth(x)
192                    )
193                })
194            },
195            x => Err(ParseError::InvalidType {
196                expected: "float or int type",
197                found: x,
198            })
199        }
200    }
201}
202/// A 32-bit unsigned integer indicating which instruction to use and determining the layout
203/// of following operands (for [`InstExtInst`]).
204pub type LiteralExtInstInteger = u32;
205/// An opcode indicating the operation to be performed and determining the layout of following
206/// operands (for [`InstSpecConstantOp`]).
207#[derive(Clone, Copy, Debug)]
208pub struct LiteralSpecConstantOpInteger<'a> {
209    pub code: Code,
210    pub operands: &'a [IdRef],
211}
212impl<'a> LiteralSpecConstantOpInteger<'a> {
213
214    pub fn parse_one(
215        stream: &mut InstructionStream<'a>,
216    ) -> ParseResult<Self>
217    {
218        Ok(Self {
219            code: Code::from_word(stream.read()?),
220            operands: IdRef::parse_eos(stream)?,
221        })
222    }
223}
224impl<'a> Display for LiteralSpecConstantOpInteger<'a> {
225
226    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227        write!(f, "{}", self.code)?;
228        for operand in self.operands {
229            write!(f, " {operand}")?;
230        }
231        Ok(())
232    }
233}
234#[repr(C)]
235#[derive(Clone, Copy, Debug)]
236pub struct Pair<T, U>(T, U)
237    where
238        T: Word + Debug + Display,
239        U: Word + Debug + Display;
240impl<T, U> Display for Pair<T, U>
241    where
242        T: Word + Debug + Display,
243        U: Word + Debug + Display,
244{
245
246    #[inline]
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        write!(f, "{} {}", self.0, self.1)
249    }
250}
251impl<'a, T, U> Pair<T, U>
252    where
253        T: Word + Debug + Display,
254        U: Word + Debug + Display,
255{
256
257    #[inline]
258    pub fn parse_one(
259        stream: &mut InstructionStream<'a>,
260    ) -> ParseResult<Self> {
261        Ok(Self(T::from_word(stream.read()?), U::from_word(stream.read()?)))
262    }
263
264    #[inline]
265    pub fn parse_eos(
266        stream: &mut InstructionStream<'a>,
267    ) -> ParseResult<&'a [Self]> {
268        let words = stream.read_words(None)?;
269        if !words.len().is_multiple_of(2) {
270            return Err(ParseError::InvalidPairWordCount(words.len() as u32))
271        }
272        unsafe {
273            Ok(slice::from_raw_parts(
274                words.as_ptr().cast(),
275                words.len() / 2
276            ))
277        }
278    }
279}
280pub type PairLiteralIntegerIdRef = Pair<LiteralInteger, IdRef>;
281pub type PairIdRefLiteralInteger = Pair<IdRef, LiteralInteger>;
282pub type PairIdRefIdRef = Pair<IdRef, IdRef>;
283#[derive(Default, Clone, Copy)]
284pub struct InstInfo {
285    pub name: &'static str,
286    pub has_id_result_type: bool,
287    pub has_id_result: bool,
288}