Skip to main content

iridia_exec/
flat.rs

1//! The flat form of a program: operations on registers of four 32-bit words, and the structured statements around
2//! them.
3
4use super::request::{Dim, ImageAtomicOp, QueryKind};
5use iridia::ResourceId;
6
7pub(super) type Reg = [u32; 4];
8
9#[derive(Clone, Copy, Debug, PartialEq)]
10pub(super) enum BinOp {
11    AddF,
12    SubF,
13    MulF,
14    DivF,
15    ModF,
16    AddU,
17    SubU,
18    MulU,
19    DivU,
20    ModU,
21    And,
22    Or,
23    Xor,
24    Shl,
25    ShrU,
26    ShrI,
27    EqW,
28    NeW,
29    EqF,
30    NeF,
31    LtF,
32    LeF,
33    GtF,
34    GeF,
35    LtU,
36    LeU,
37    GtU,
38    GeU,
39    LtI,
40    LeI,
41    GtI,
42    GeI,
43    LAnd,
44    LOr,
45}
46#[derive(Clone, Copy, Debug, PartialEq)]
47pub(super) enum UnOp {
48    NegF,
49    NegI,
50    Not,
51    BitNot,
52}
53#[derive(Clone, Copy, Debug, PartialEq)]
54pub(super) enum CvtOp {
55    F2I,
56    F2U,
57    I2F,
58    U2F,
59    /// A boolean (a word that is 0 or not) as 1.0 or 0.0, and as 1 or 0.
60    B2F,
61    B2U,
62}
63#[derive(Clone, Copy, Debug, PartialEq)]
64pub(super) enum MathOp {
65    AbsF,
66    AbsI,
67    MinF,
68    MaxF,
69    MinU,
70    MaxU,
71    MinI,
72    MaxI,
73    ClampF,
74    SatF,
75    Floor,
76    Ceil,
77    Trunc,
78    Round,
79    Fract,
80    Exp2,
81    Log2,
82    Sin,
83    Cos,
84    QuantizeF16,
85    Tan,
86    Asin,
87    Acos,
88    Atan,
89    Sinh,
90    Cosh,
91    Tanh,
92    Fma,
93    Sqrt,
94    Rsqrt,
95    Dot,
96    Popcnt,
97    RevBits,
98    Clz,
99    Ctz,
100    PackHalf,
101    UnpackHalf,
102    /// `mix(x, y, a)`: `x * (1 - a) + y * a`.
103    Mix,
104    /// The vector scaled to length 1.
105    Normalize,
106    /// `pow(x, y)`, evaluated in double precision and rounded once.
107    Pow,
108    SignF,
109    SignI,
110    /// The relational functions: whether all or any lane of a boolean vector is set, and per lane whether a float is a
111    /// NaN or an infinity.
112    All,
113    Any,
114    IsNan,
115    IsInf,
116}
117
118#[derive(Clone, Copy, Debug)]
119pub(super) enum Loc {
120    Local(u32),
121    Global(u32, u32),
122    /// Words from the offset of one element of an array of buffers (a global that is a binding array): the element
123    /// is fixed, or read from the first lane of a register.
124    Elem(u32, u32, Pick),
125}
126impl Loc {
127    /// The register an element index of this location is read from.
128    pub(super) fn slot(&self) -> Option<u32> {
129        match self {
130            Loc::Elem(_, _, Pick::Slot(s)) => Some(*s),
131            _ => None,
132        }
133    }
134}
135#[derive(Clone, Copy, Debug)]
136pub(super) struct Ptr {
137    pub loc: Loc,
138    /// Slot of the index register, words per index step, element count.
139    pub dynamic: Option<(u32, u32, u32)>,
140}
141
142#[derive(Clone, Debug)]
143pub(super) enum Op {
144    Swizzle {
145        src: u32,
146        pat: [u8; 4],
147        n: u8,
148    },
149    Splat {
150        src: u32,
151        n: u8,
152    },
153    Compose {
154        parts: [(u32, u8); 4],
155        np: u8,
156    },
157    Lane {
158        src: u32,
159        i: u8,
160    },
161    Load {
162        loc: Loc,
163        n: u8,
164    },
165    LoadLanes {
166        loc: Loc,
167        offs: [u8; 4],
168        n: u8,
169    },
170    LoadDyn {
171        ptr: Ptr,
172        n: u8,
173    },
174    Un {
175        op: UnOp,
176        src: u32,
177        n: u8,
178    },
179    Bin {
180        op: BinOp,
181        a: u32,
182        b: u32,
183        n: u8,
184        a1: bool,
185        b1: bool,
186    },
187    Select {
188        c: u32,
189        a: u32,
190        b: u32,
191        n: u8,
192        c1: bool,
193    },
194    Cvt {
195        op: CvtOp,
196        src: u32,
197        n: u8,
198    },
199    Math {
200        f: MathOp,
201        a: u32,
202        b: u32,
203        c: u32,
204        n: u8,
205        /// The third operand is a scalar given to every lane (`mix` of vectors by a scalar).
206        c1: bool,
207    },
208    Deriv {
209        src: u32,
210        axis: u8,
211        fine: bool,
212        n: u8,
213        prov: Option<[(u32, u8); 4]>,
214    },
215    Sample {
216        tex: Res,
217        smp: Res,
218        coord: u32,
219        cn: u8,
220        layer: Option<u32>,
221        level: LevelOp,
222        dim: Dim,
223        offset: [i32; 3],
224        gather: Option<u8>,
225        depth_ref: Option<u32>,
226        depth: bool,
227    },
228    Texel {
229        tex: Res,
230        coord: u32,
231        cn: u8,
232        dim: Dim,
233        storage: bool,
234        layer: Option<u32>,
235        sample: Option<u32>,
236        mip: Option<u32>,
237    },
238    Query {
239        tex: Res,
240        dim: Dim,
241        kind: QueryKind,
242        level: Option<u32>,
243    },
244    /// Copy words of local memory (a whole array about to be returned, as it is now).
245    CopyWords {
246        src: Loc,
247        dst: u32,
248        words: u32,
249    },
250    /// The intersection a ray query reports: seventeen consecutive registers from `first`, in order the kind, t, custom
251    /// data, instance index, record offset, geometry index, primitive index, barycentrics, front face, then the four
252    /// columns of object to world and of world to object.
253    RqHit {
254        q: u32,
255        committed: bool,
256        first: u32,
257    },
258    ArrLen {
259        gid: u32,
260        elem_words: u32,
261        /// The element of an array of buffers.
262        pick: Option<Pick>,
263    },
264}
265/// Which element of a resource array an operation reads.
266#[derive(Clone, Copy, Debug)]
267pub(super) enum Pick {
268    /// The resource is not an array.
269    One,
270    Fixed(u32),
271    /// The first lane of a register, per invocation.
272    Slot(u32),
273}
274/// A resource an operation names, and for an array the element it picks and how many there are.
275#[derive(Clone, Copy, Debug)]
276pub(super) struct Res {
277    pub id: ResourceId,
278    pub pick: Pick,
279    pub count: u32,
280}
281impl Res {
282    /// The register an element index is read from.
283    pub(super) fn slot(&self) -> Option<u32> {
284        match self.pick {
285            Pick::Slot(s) => Some(s),
286            _ => None,
287        }
288    }
289}
290#[derive(Clone, Copy, Debug)]
291pub(super) enum LevelOp {
292    Auto,
293    Zero,
294    Exact(u32),
295    Bias(u32),
296    Gradient(u32, u32),
297}
298
299/// One member of a function's result: a register, or the elements of an array in the invocation's local memory (each
300/// element comes out as an entry of its own).
301#[derive(Clone, Copy, Debug)]
302pub(super) enum Member {
303    Reg(u32, u8),
304    /// `keep` is the register of the copy that made them, which a dead-operation pass must not drop.
305    Mem {
306        word: u32,
307        count: u32,
308        width: u8,
309        keep: Option<u32>,
310    },
311}
312
313#[derive(Clone, Debug)]
314pub(super) enum St {
315    Run(u32, u32),
316    Store {
317        loc: Loc,
318        src: u32,
319        n: u8,
320    },
321    StoreDyn {
322        ptr: Ptr,
323        src: u32,
324        n: u8,
325    },
326    ImageStore {
327        tex: Res,
328        dim: Dim,
329        coord: u32,
330        cn: u8,
331        layer: Option<u32>,
332        value: u32,
333        vn: u8,
334    },
335    ImageAtomic {
336        tex: Res,
337        dim: Dim,
338        coord: u32,
339        cn: u8,
340        layer: Option<u32>,
341        op: ImageAtomicOp,
342        signed: bool,
343        value: u32,
344        /// The register that takes the word as it was before, where the program reads it.
345        result: Option<u32>,
346    },
347    Atomic {
348        ptr: Ptr,
349        fun: AtomOp,
350        /// Min and max compare as signed integers.
351        signed: bool,
352        value: u32,
353        /// The expected value of a compare-exchange.
354        compare: Option<u32>,
355        /// The value the word held, and for a compare-exchange whether it was exchanged.
356        result: Option<u32>,
357        exchanged: Option<u32>,
358    },
359    /// A group barrier: every live invocation of the group must reach it together.
360    Barrier,
361    /// Write the members of an aggregate value to consecutive words of memory.
362    StoreAgg {
363        loc: Loc,
364        members: Vec<(u32, u8)>,
365    },
366    /// Start the ray query `q` on the acceleration structure `scene`, the ray in these registers.
367    RqInit {
368        q: u32,
369        scene: ResourceId,
370        flags: u32,
371        mask: u32,
372        tmin: u32,
373        tmax: u32,
374        origin: u32,
375        direction: u32,
376    },
377    RqProceed {
378        q: u32,
379        result: u32,
380    },
381    RqConfirm {
382        q: u32,
383    },
384    /// `TraceRay`: the ray's registers (flags, mask, hit group offset and stride, miss index, origin, t min, direction,
385    /// t max) and the payload's words in local memory.
386    RtTrace {
387        scene: ResourceId,
388        operands: [u32; 9],
389        payload: (u32, u32),
390    },
391    /// `ReportHit`: t, hit kind, the attributes' words in local memory, and the register that takes whether it was
392    /// accepted.
393    RtReport {
394        t: u32,
395        kind: u32,
396        attributes: (u32, u32),
397        result: Option<u32>,
398    },
399    /// `CallShader`: the shader index and the parameter's words in local memory.
400    RtCall {
401        index: u32,
402        parameter: (u32, u32),
403    },
404    /// `IgnoreHit` and `AcceptHitAndEndSearch`: what the any-hit program decided.
405    RtDecide(super::run::Decision),
406    /// Commit the procedural candidate at the distance in this register.
407    RqGenerate {
408        q: u32,
409        t: u32,
410    },
411    RqTerminate {
412        q: u32,
413    },
414    /// A bitmask of the wave's active lanes whose predicate holds (four words), for each lane of the wave.
415    WaveBallot {
416        predicate: Option<u32>,
417        result: u32,
418    },
419    /// A value taken from another lane of the wave.
420    WaveGather {
421        mode: WaveGather,
422        value: u32,
423        n: u8,
424        result: u32,
425    },
426    /// A reduction or scan of a value over the wave's active lanes.
427    WaveOp {
428        op: WaveOp,
429        scan: WaveScan,
430        value: u32,
431        n: u8,
432        kind: WaveKind,
433        result: u32,
434    },
435    If {
436        c: u32,
437        a: Vec<St>,
438        r: Vec<St>,
439    },
440    Loop {
441        body: Vec<St>,
442        cont: Vec<St>,
443        break_if: Option<u32>,
444    },
445    Switch {
446        sel: u32,
447        cases: Vec<(Option<u32>, bool, Vec<St>)>,
448    },
449    Break,
450    Continue,
451    /// Leave, with these members as the result (in the order of the interface's outputs).
452    Return(Vec<Member>),
453    Kill,
454}
455
456/// Where a wave gather reads from; a slot names the register holding the lane, delta or mask (first lane of it).
457#[derive(Clone, Copy, Debug, PartialEq)]
458pub(super) enum WaveGather {
459    First,
460    Lane(u32),
461    Shuffle(u32),
462    Down(u32),
463    Up(u32),
464    Xor(u32),
465    QuadLane(u32),
466    /// The quad neighbour along x (1), y (2) or the diagonal (3): the lane xor this.
467    QuadSwap(u32),
468}
469#[derive(Clone, Copy, Debug, PartialEq)]
470pub(super) enum WaveOp {
471    All,
472    Any,
473    Add,
474    Mul,
475    Min,
476    Max,
477    And,
478    Or,
479    Xor,
480}
481#[derive(Clone, Copy, Debug, PartialEq)]
482pub(super) enum WaveScan {
483    Reduce,
484    Inclusive,
485    Exclusive,
486}
487#[derive(Clone, Copy, Debug, PartialEq)]
488pub(super) enum WaveKind {
489    F,
490    U,
491    I,
492}
493
494#[derive(Clone, Copy, Debug, PartialEq)]
495pub(super) enum AtomOp {
496    Add,
497    Sub,
498    And,
499    Or,
500    Xor,
501    Min,
502    Max,
503    Exchange,
504    CompareExchange,
505}
506
507#[derive(Clone, Debug)]
508pub(super) enum GlobalKind {
509    /// A constant buffer of the interface.
510    Constants(ResourceId),
511    ConstantsArray(ResourceId, u32),
512    /// Private data: an immediate constant buffer's words.
513    Private(Vec<u32>),
514    /// A buffer of the interface read through the storage address space.
515    Storage(ResourceId),
516    /// An array of that many such buffers.
517    StorageArray(ResourceId, u32),
518    /// Thread-group memory of this many words, zero at the start of every group.
519    Workgroup(u32),
520}
521#[derive(Clone, Debug)]
522pub(super) struct GlobalDesc {
523    pub kind: GlobalKind,
524    /// Words of one element of the global's array (1 for anything else).
525    pub elem_words: u32,
526}
527
528/// A program compiled once into a flat form: typed operations on four-lane word registers, static pointer arithmetic
529/// folded, bitcasts aliased, dead operations removed. Running it is [`Runner`](super::Runner)'s.
530#[derive(Debug)]
531pub struct Executable {
532    pub(super) ops: Vec<(u32, Op)>,
533    pub(super) body: Vec<St>,
534    pub(super) slots: usize,
535    pub(super) inits: Vec<(u32, Reg)>,
536    /// Per entry argument: its slot and lanes (none for an array argument, or one nothing reads).
537    pub(super) args: Vec<(u32, u8)>,
538    /// Per argument, where its registers start among those the caller passes (an array argument takes one per
539    /// element), and how many there are in all.
540    pub(super) arg_at: Vec<usize>,
541    pub(super) arg_len: usize,
542    /// The pointer arguments (a ray tracing program's payload and attributes): where their words start among the passed
543    /// registers (four words to a register), their words in local memory and how many there are.
544    pub(super) pointer_args: Vec<(usize, u32, u32)>,
545    /// The array arguments: where they start among the passed registers, their words in local memory, their element
546    /// count and element width.
547    pub(super) array_args: Vec<(usize, u32, u32, u8)>,
548    pub(super) local_words: usize,
549    pub(super) globals: Vec<GlobalDesc>,
550    /// Whether 32-bit denormals are flushed to zero (the program's D3D modes).
551    pub(super) flush_denormals: bool,
552    /// The thread group of a compute or mesh program.
553    pub(super) workgroup: Option<[u32; 3]>,
554    /// A mesh program's output variable: its index among the globals and its words.
555    pub(super) mesh_output: Option<(usize, u32)>,
556    /// Per entry argument, the built-in it carries.
557    pub(super) builtins: Vec<Option<naga::BuiltIn>>,
558}