Skip to main content

iridia/build/
mod.rs

1//! A typed builder over naga's IR for lifters. Every value it hands out carries its scalar kind and width, so a lifter
2//! never asks naga's typifier and a bitcast or splat is explicit where it is needed. Nothing here knows a bytecode;
3//! [`behaviour`] holds D3D's results spelled out as operations.
4
5mod atomic;
6pub mod behaviour;
7mod entry;
8mod mesh;
9pub mod structure;
10
11pub use entry::{EntryDecl, FunctionDecl};
12pub use mesh::MeshOutput;
13
14use naga::{
15    BinaryOperator, Block, Expression, Function, GlobalVariable, Handle, Literal, LocalVariable,
16    MathFunction, Module, Scalar, ScalarKind, Span, Statement, SwizzleComponent, Type, TypeInner,
17    UnaryOperator, VectorSize,
18};
19
20/// The scalar kind of a typed value: unsigned, signed, float or bool.
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub enum Kind {
23    /// Unsigned 32-bit integer.
24    U,
25    /// Signed 32-bit integer.
26    I,
27    /// 32-bit float.
28    F,
29    /// Boolean.
30    B,
31}
32impl Kind {
33    /// The naga scalar this kind is carried as (32 bits wide; a bool is a bool).
34    pub fn scalar(self) -> Scalar {
35        match self {
36            Kind::U => Scalar::U32,
37            Kind::I => Scalar::I32,
38            Kind::F => Scalar::F32,
39            Kind::B => Scalar::BOOL,
40        }
41    }
42    /// The naga scalar kind of [`Kind::scalar`].
43    pub fn kind(self) -> ScalarKind {
44        self.scalar().kind
45    }
46}
47
48/// How many lanes a value has: one (a scalar) to four. There is no other width, so every type and vector the builder
49/// is asked for is one naga has.
50#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub enum Width {
52    /// A scalar.
53    One = 1,
54    /// A vector of two lanes.
55    Two = 2,
56    /// A vector of three lanes.
57    Three = 3,
58    /// A vector of four lanes.
59    Four = 4,
60}
61impl Width {
62    /// Every width, from one lane to four.
63    pub const ALL: [Width; 4] = [Width::One, Width::Two, Width::Three, Width::Four];
64
65    /// The width of `lanes` lanes, `None` unless it is 1 to 4.
66    pub const fn new(lanes: u8) -> Option<Width> {
67        match lanes {
68            1 => Some(Width::One),
69            2 => Some(Width::Two),
70            3 => Some(Width::Three),
71            4 => Some(Width::Four),
72            _ => None,
73        }
74    }
75
76    /// The width of a count of lanes, `None` unless it is 1 to 4.
77    pub fn of_count(lanes: usize) -> Option<Width> {
78        u8::try_from(lanes).ok().and_then(Width::new)
79    }
80
81    /// The width of a naga vector of `size`.
82    pub const fn of_vector(size: VectorSize) -> Width {
83        match size {
84            VectorSize::Bi => Width::Two,
85            VectorSize::Tri => Width::Three,
86            VectorSize::Quad => Width::Four,
87        }
88    }
89
90    /// The number of lanes, 1 to 4.
91    pub const fn get(self) -> u8 {
92        self as u8
93    }
94
95    /// The number of lanes, 1 to 4, as a count.
96    pub const fn count(self) -> usize {
97        self as usize
98    }
99
100    /// The naga vector size of the width, `None` for a scalar.
101    pub const fn vector_size(self) -> Option<VectorSize> {
102        match self {
103            Width::One => None,
104            Width::Two => Some(VectorSize::Bi),
105            Width::Three => Some(VectorSize::Tri),
106            Width::Four => Some(VectorSize::Quad),
107        }
108    }
109
110    /// The lanes of the width, 0 to one less than it.
111    pub fn lanes(self) -> std::ops::Range<u8> {
112        0..self.get()
113    }
114}
115impl From<Width> for u8 {
116    fn from(w: Width) -> u8 {
117        w.get()
118    }
119}
120impl From<Width> for u32 {
121    fn from(w: Width) -> u32 {
122        u32::from(w.get())
123    }
124}
125impl From<Width> for usize {
126    fn from(w: Width) -> usize {
127        w.count()
128    }
129}
130impl From<VectorSize> for Width {
131    fn from(size: VectorSize) -> Width {
132        Width::of_vector(size)
133    }
134}
135impl TryFrom<u8> for Width {
136    type Error = String;
137    fn try_from(lanes: u8) -> Result<Width, String> {
138        Width::new(lanes).ok_or_else(|| format!("a width of {lanes} lanes (a value has 1 to 4)"))
139    }
140}
141impl TryFrom<u32> for Width {
142    type Error = String;
143    fn try_from(lanes: u32) -> Result<Width, String> {
144        u8::try_from(lanes)
145            .ok()
146            .and_then(Width::new)
147            .ok_or_else(|| format!("a width of {lanes} lanes (a value has 1 to 4)"))
148    }
149}
150impl TryFrom<usize> for Width {
151    type Error = String;
152    fn try_from(lanes: usize) -> Result<Width, String> {
153        Width::of_count(lanes).ok_or_else(|| format!("a width of {lanes} lanes (a value has 1 to 4)"))
154    }
155}
156impl std::fmt::Display for Width {
157    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158        write!(f, "{}", self.get())
159    }
160}
161
162/// An expression with its kind and width.
163#[derive(Clone, Copy, Debug)]
164pub struct Val {
165    /// The expression holding the value.
166    pub expr: Handle<Expression>,
167    /// The scalar kind of every lane.
168    pub kind: Kind,
169    /// The number of lanes.
170    pub width: Width,
171}
172
173/// `offset` rounded up to a multiple of `align`, or the reason it does not fit in 32 bits.
174pub(crate) fn align_up(offset: u32, align: u32) -> Result<u32, String> {
175    offset.checked_next_multiple_of(align).ok_or_else(|| {
176        format!("a layout offset of {offset} bytes aligned to {align} is over 4294967295 bytes")
177    })
178}
179
180/// `value`, or the reason a layout size does not fit in 32 bits.
181pub(crate) fn fits(value: Option<u32>) -> Result<u32, String> {
182    value.ok_or_else(|| "a layout of over 4294967295 bytes".to_owned())
183}
184
185/// The swizzle component for lane 0 (x) to 3 (w); any larger lane is w.
186pub fn component(lane: u8) -> SwizzleComponent {
187    match lane {
188        0 => SwizzleComponent::X,
189        1 => SwizzleComponent::Y,
190        2 => SwizzleComponent::Z,
191        _ => SwizzleComponent::W,
192    }
193}
194
195/// A module and the entry function being built, with a stack of the blocks open for structured control flow.
196///
197/// What a lifter reads decides the shapes of the values it hands the builder, so an operation asked of values that cannot
198/// do it (a vector of 2 lanes added to one of 3) is not a bug of the builder and does not panic: it records the first such
199/// fault and returns a value of the shape asked for. The contract is the lifter's: it calls [`Builder::check`] where it
200/// can name what it was reading (after each instruction or statement), and turns a fault into a refusal. `finish`,
201/// `finish_mesh`, `finish_functions` and `end_function` give back a fault nobody checked, or control flow left open, as an
202/// error: a lifter that follows the contract does not see one from its input, but a lifter's own bug is an error to
203/// refuse the program with, not a panic.
204#[derive(Debug)]
205pub struct Builder {
206    /// The module being built.
207    pub module: Module,
208    /// The entry function being built (its body is assembled from [`Builder::blocks`] when the module is finished).
209    pub function: Function,
210    /// The blocks being filled, innermost last; statements go to the last.
211    pub blocks: Vec<Block>,
212    /// A compute entry point's thread group size (set before [`Builder::finish`]; 0 for the other stages).
213    pub workgroup_size: [u32; 3],
214    /// The first operation a lifter asked for that the values it was given cannot be (a vector of 2 lanes added to one
215    /// of 3, a lane that is not there): the lifter's input is at fault, not the builder, so the operation hands back a
216    /// value of the shape it was asked for and the fault waits here until the lifter asks ([`Builder::check`]).
217    error: Option<String>,
218}
219impl Default for Builder {
220    fn default() -> Self {
221        Self::new()
222    }
223}
224impl Builder {
225    /// A builder over an empty module with one open block.
226    pub fn new() -> Self {
227        Self {
228            module: Module::default(),
229            function: Function::default(),
230            blocks: vec![Block::new()],
231            workgroup_size: [0; 3],
232            error: None,
233        }
234    }
235
236    /// Record that an operation was asked of values that cannot do it; the first is kept.
237    fn fail(&mut self, detail: impl Into<String>) {
238        self.error.get_or_insert_with(|| detail.into());
239    }
240
241    /// The first fault of the operations since the last check, which a lifter turns into a refusal of the program at the
242    /// place it is reading. A builder with a fault unchecked cannot be finished: that is the lifter's bug.
243    pub fn check(&mut self) -> Result<(), String> {
244        self.error.take().map_or(Ok(()), Err)
245    }
246
247    /// Whether the builder can be finished: its control flow closed, and no fault left unchecked.
248    fn finishable(&mut self) -> Result<(), String> {
249        if self.blocks.len() != 1 {
250            return Err(format!(
251                "control flow left open: {} blocks open where the function's own is the one (a lifter bug)",
252                self.blocks.len()
253            ));
254        }
255        self.check()
256            .map_err(|fault| format!("a fault the lifter did not check before finishing: {fault}"))
257    }
258
259    /// The type `inner` in the module (types equal to an earlier one are shared).
260    pub fn ty(&mut self, inner: TypeInner) -> Handle<Type> {
261        self.module
262            .types
263            .insert(Type { name: None, inner }, Span::UNDEFINED)
264    }
265    /// The type of a value of `kind` and `width` lanes: a scalar for one.
266    pub fn ty_of(&mut self, kind: Kind, width: Width) -> Handle<Type> {
267        match width.vector_size() {
268            None => self.ty(TypeInner::Scalar(kind.scalar())),
269            Some(size) => self.ty(TypeInner::Vector {
270                size,
271                scalar: kind.scalar(),
272            }),
273        }
274    }
275
276    /// Append an expression to the function; one that is not a pre-emitted kind (a literal, an argument, a pointer)
277    /// is emitted in the current block.
278    pub fn app(&mut self, e: Expression) -> Handle<Expression> {
279        let pre = e.needs_pre_emit();
280        let start = self.function.expressions.len();
281        let h = self.function.expressions.append(e, Span::UNDEFINED);
282        if !pre {
283            let range = self.function.expressions.range_from(start);
284            self.push(Statement::Emit(range));
285        }
286        h
287    }
288    /// The type of an element of a typed buffer the program reaches with atomic operations: four atomic words.
289    pub fn atomic_quad(&mut self, scalar: naga::Scalar) -> Handle<Type> {
290        let atomic = self.ty(TypeInner::Atomic(scalar));
291        let members = (0..4u32)
292            .map(|k| naga::StructMember {
293                name: Some(format!("w{k}")),
294                ty: atomic,
295                binding: None,
296                offset: k.saturating_mul(4),
297            })
298            .collect();
299        self.ty(TypeInner::Struct { members, span: 16 })
300    }
301    /// A result expression (an atomic's old value): made before the statement that fills it, covered by no emit.
302    pub fn result_expr(&mut self, e: Expression) -> Handle<Expression> {
303        self.function.expressions.append(e, Span::UNDEFINED)
304    }
305    /// `if condition { then }`: what `then` appends goes in the accept block.
306    pub fn when(&mut self, condition: Val, then: impl FnOnce(&mut Self)) {
307        self.blocks.push(Block::new());
308        then(self);
309        let accept = self.blocks.pop().expect("the block just pushed");
310        self.push(Statement::If {
311            condition: condition.expr,
312            accept,
313            reject: Block::new(),
314        });
315    }
316    /// Open `for i in 0..count { .. }` as a loop (not unrolled): what is appended until [`Self::end_repeat`] is its
317    /// body, and the value returned is `i`, read at the top of each pass.
318    pub fn begin_repeat(&mut self, count: u32) -> (Val, Handle<LocalVariable>) {
319        let ty = self.ty_of(Kind::U, Width::One);
320        let counter = self.local("i", ty);
321        let ptr = self.local_ptr(counter);
322        let zero = self.lit_u(0);
323        self.store(ptr, zero);
324        self.blocks.push(Block::new());
325        let i = self.load(ptr, Kind::U, Width::One);
326        let limit = self.lit_u(count);
327        let done = self.binary(BinaryOperator::GreaterEqual, i, limit);
328        self.when(done, |b| b.push(Statement::Break));
329        (i, counter)
330    }
331    /// Close the loop [`Self::begin_repeat`] opened: count the pass and go round.
332    pub fn end_repeat(&mut self, counter: Handle<LocalVariable>) {
333        let ptr = self.local_ptr(counter);
334        let again = self.load(ptr, Kind::U, Width::One);
335        let one = self.lit_u(1);
336        let next = self.binary(BinaryOperator::Add, again, one);
337        self.store(ptr, next);
338        let inner = self.blocks.pop().expect("the loop body opened by begin_repeat");
339        self.push(Statement::Loop {
340            body: inner,
341            continuing: Block::new(),
342            break_if: None,
343        });
344    }
345    /// Append `s` to the innermost open block.
346    pub fn push(&mut self, s: Statement) {
347        self.blocks
348            .last_mut()
349            .expect("a block is always open")
350            .push(s, Span::UNDEFINED);
351    }
352    /// A new local variable of the function, named `name` and uninitialised.
353    pub fn local(&mut self, name: &str, ty: Handle<Type>) -> Handle<LocalVariable> {
354        self.function.local_variables.append(
355            LocalVariable {
356                name: Some(name.to_owned()),
357                ty,
358                init: None,
359            },
360            Span::UNDEFINED,
361        )
362    }
363    /// A pointer expression to the local variable `l`.
364    pub fn local_ptr(&mut self, l: Handle<LocalVariable>) -> Handle<Expression> {
365        self.app(Expression::LocalVariable(l))
366    }
367    /// A pointer expression to the global variable `g`.
368    pub fn global_ptr(&mut self, g: Handle<GlobalVariable>) -> Handle<Expression> {
369        self.app(Expression::GlobalVariable(g))
370    }
371    /// A load through `ptr`, typed by the `kind` and `width` the caller states the pointee has.
372    pub fn load(&mut self, ptr: Handle<Expression>, kind: Kind, width: Width) -> Val {
373        Val {
374            expr: self.app(Expression::Load { pointer: ptr }),
375            kind,
376            width,
377        }
378    }
379    /// Store `v` through `ptr`.
380    pub fn store(&mut self, ptr: Handle<Expression>, v: Val) {
381        self.push(Statement::Store {
382            pointer: ptr,
383            value: v.expr,
384        });
385    }
386    /// Add the global variable `g` to the module.
387    pub fn global(&mut self, g: GlobalVariable) -> Handle<GlobalVariable> {
388        self.module.global_variables.append(g, Span::UNDEFINED)
389    }
390    /// An expression of the module's constant arena (an initialiser).
391    pub fn global_expr(&mut self, e: Expression) -> Handle<Expression> {
392        self.module.global_expressions.append(e, Span::UNDEFINED)
393    }
394
395    // literals
396    /// An unsigned integer literal.
397    pub fn lit_u(&mut self, x: u32) -> Val {
398        self.lit(Literal::U32(x), Kind::U)
399    }
400    /// A signed integer literal.
401    pub fn lit_i(&mut self, x: i32) -> Val {
402        self.lit(Literal::I32(x), Kind::I)
403    }
404    /// A float literal. naga holds only finite ones, so a NaN or an infinity is the bits of one, reinterpreted.
405    pub fn lit_f(&mut self, x: f32) -> Val {
406        if x.is_finite() {
407            return self.lit(Literal::F32(x), Kind::F);
408        }
409        let bits = self.lit_u(x.to_bits());
410        self.bitcast(bits, Kind::F)
411    }
412    /// A boolean literal.
413    pub fn lit_b(&mut self, x: bool) -> Val {
414        self.lit(Literal::Bool(x), Kind::B)
415    }
416    fn lit(&mut self, l: Literal, kind: Kind) -> Val {
417        Val {
418            expr: self.app(Expression::Literal(l)),
419            kind,
420            width: Width::One,
421        }
422    }
423    /// The literal of `kind` whose 32 bits are `bits` (a bool is whether they are nonzero).
424    pub fn lit_bits(&mut self, kind: Kind, bits: u32) -> Val {
425        match kind {
426            Kind::U => self.lit_u(bits),
427            Kind::I => self.lit_i(bits as i32),
428            Kind::F => self.lit_f(f32::from_bits(bits)),
429            Kind::B => self.lit_b(bits != 0),
430        }
431    }
432
433    /// `v` repeated across `width` lanes; `v` itself when it already has that many. A `v` that is not a scalar
434    /// records a fault ([`Builder::check`]) and gives `v` back.
435    pub fn splat(&mut self, v: Val, width: Width) -> Val {
436        if v.width == width {
437            return v;
438        }
439        let Some(size) = width.vector_size().filter(|_| v.width == Width::One) else {
440            self.fail(format!("a value of {} lanes where {width} are needed", v.width));
441            return v;
442        };
443        Val {
444            expr: self.app(Expression::Splat { size, value: v.expr }),
445            kind: v.kind,
446            width,
447        }
448    }
449    /// A vector (or the scalar itself, for one part) from scalars of one kind.
450    pub fn compose(&mut self, parts: &[Val]) -> Val {
451        if let [only] = parts {
452            return *only;
453        }
454        let Some(first) = parts.first() else {
455            self.fail("a vector of no lanes");
456            return self.lit_u(0);
457        };
458        let Some(width) = Width::of_count(parts.len()).filter(|_| {
459            parts
460                .iter()
461                .all(|p| p.width == Width::One && p.kind == first.kind)
462        }) else {
463            self.fail(format!(
464                "a vector of {} parts that are not scalars of one kind",
465                parts.len()
466            ));
467            return *first;
468        };
469        let kind = first.kind;
470        let ty = self.ty_of(kind, width);
471        Val {
472            expr: self.app(Expression::Compose {
473                ty,
474                components: parts.iter().map(|p| p.expr).collect(),
475            }),
476            kind,
477            width,
478        }
479    }
480    /// Lane `i` of a vector.
481    pub fn lane(&mut self, v: Val, i: u8) -> Val {
482        if i >= v.width.get() {
483            self.fail(format!("lane {i} of a value of {} lanes", v.width));
484            return v;
485        }
486        if v.width == Width::One {
487            return v;
488        }
489        Val {
490            expr: self.app(Expression::AccessIndex {
491                base: v.expr,
492                index: u32::from(i),
493            }),
494            kind: v.kind,
495            width: Width::One,
496        }
497    }
498    /// Lanes `lanes` of a vector, in that order, repeats allowed; a scalar is splat.
499    pub fn swizzle(&mut self, v: Val, lanes: &[u8]) -> Val {
500        if let [one] = lanes {
501            return self.lane(v, *one);
502        }
503        let Some(width) = Width::of_count(lanes.len()).filter(|_| lanes.iter().all(|l| *l < v.width.get()))
504        else {
505            self.fail(format!("lanes {lanes:?} of a value of {} lanes", v.width));
506            return v;
507        };
508        if v.width == Width::One {
509            return self.splat(v, width);
510        }
511        let Some(size) = width.vector_size() else {
512            // one lane is `lane`'s
513            return self.lane(v, lanes.first().copied().unwrap_or(0));
514        };
515        let mut pattern = [SwizzleComponent::X; 4];
516        for (slot, lane) in pattern.iter_mut().zip(lanes) {
517            *slot = component(*lane);
518        }
519        Val {
520            expr: self.app(Expression::Swizzle {
521                size,
522                vector: v.expr,
523                pattern,
524            }),
525            kind: v.kind,
526            width,
527        }
528    }
529    /// Reinterpret the bits as another kind (u32, i32 or f32), width unchanged.
530    pub fn bitcast(&mut self, v: Val, kind: Kind) -> Val {
531        if v.kind == kind {
532            return v;
533        }
534        Val {
535            expr: self.app(Expression::As {
536                expr: v.expr,
537                kind: kind.kind(),
538                convert: None,
539            }),
540            kind,
541            width: v.width,
542        }
543    }
544    /// The value as `kind`: a bitcast between u32, i32 and f32; a bool becomes a word of all ones or zero (D3D's
545    /// true and false) and a word a bool by being nonzero.
546    pub fn bitcast_to(&mut self, v: Val, kind: Kind) -> Val {
547        match (v.kind, kind) {
548            (a, b) if a == b => v,
549            (Kind::B, _) => {
550                let ones = self.lit_u(u32::MAX);
551                let zero = self.lit_u(0);
552                let word = self.select(v, ones, zero);
553                self.bitcast(word, kind)
554            }
555            (_, Kind::B) => {
556                let word = self.bitcast(v, Kind::U);
557                let zero = self.lit_u(0);
558                self.binary(BinaryOperator::NotEqual, word, zero)
559            }
560            _ => self.bitcast(v, kind),
561        }
562    }
563    /// Convert the value to another kind (`itof`, `utof`, float to integer) with naga's own semantics; D3D's differ
564    /// for float to integer and are [`behaviour`].
565    pub fn convert(&mut self, v: Val, kind: Kind) -> Val {
566        Val {
567            expr: self.app(Expression::As {
568                expr: v.expr,
569                kind: kind.kind(),
570                convert: Some(4),
571            }),
572            kind,
573            width: v.width,
574        }
575    }
576    /// A unary operation; the result has `v`'s kind and width.
577    pub fn unary(&mut self, op: UnaryOperator, v: Val) -> Val {
578        Val {
579            expr: self.app(Expression::Unary { op, expr: v.expr }),
580            kind: v.kind,
581            width: v.width,
582        }
583    }
584    /// A binary operation; a scalar operand is splat to the other's width, a comparison gives a bool.
585    pub fn binary(&mut self, op: BinaryOperator, a: Val, b: Val) -> Val {
586        let width = a.width.max(b.width);
587        let (a, b) = (self.splat(a, width), self.splat(b, width));
588        let kind = match op {
589            BinaryOperator::Equal
590            | BinaryOperator::NotEqual
591            | BinaryOperator::Less
592            | BinaryOperator::LessEqual
593            | BinaryOperator::Greater
594            | BinaryOperator::GreaterEqual => Kind::B,
595            _ => a.kind,
596        };
597        Val {
598            expr: self.app(Expression::Binary {
599                op,
600                left: a.expr,
601                right: b.expr,
602            }),
603            kind,
604            width,
605        }
606    }
607    /// A math function of `args` (a scalar among vectors is splat to their width). The result is a scalar for `Dot`, a
608    /// `u32` for `Pack2x16float`, two floats for `Unpack2x16float` and otherwise has the first argument's kind and the
609    /// widest width. No arguments records a fault ([`Builder::check`]).
610    pub fn math(&mut self, fun: MathFunction, args: &[Val]) -> Val {
611        let Some(width) = args.iter().map(|a| a.width).max() else {
612            self.fail("a math function of no arguments");
613            return self.lit_u(0);
614        };
615        let args: Vec<Val> = args.iter().map(|a| self.splat(*a, width)).collect();
616        let Some(first) = args.first().copied() else {
617            self.fail("a math function of no arguments");
618            return self.lit_u(0);
619        };
620        let kind = first.kind;
621        let arg = |i: usize| args.get(i).map(|a| a.expr);
622        let (width, kind) = match fun {
623            MathFunction::Dot => (Width::One, kind),
624            MathFunction::Pack2x16float => (Width::One, Kind::U),
625            MathFunction::Unpack2x16float => (Width::Two, Kind::F),
626            _ => (width, kind),
627        };
628        Val {
629            expr: self.app(Expression::Math {
630                fun,
631                arg: first.expr,
632                arg1: arg(1),
633                arg2: arg(2),
634                arg3: arg(3),
635            }),
636            kind,
637            width,
638        }
639    }
640    /// `select(reject, accept, cond)`: a scalar condition is splat to the operands' width.
641    pub fn select(&mut self, cond: Val, accept: Val, reject: Val) -> Val {
642        let width = accept.width.max(reject.width).max(cond.width);
643        let (accept, reject) = (self.splat(accept, width), self.splat(reject, width));
644        let cond = self.splat(cond, width);
645        Val {
646            expr: self.app(Expression::Select {
647                condition: cond.expr,
648                accept: accept.expr,
649                reject: reject.expr,
650            }),
651            kind: accept.kind,
652            width,
653        }
654    }
655    /// A comparison result as D3D's mask: all ones where true, else zero.
656    pub fn mask_of(&mut self, cond: Val) -> Val {
657        let ones = self.lit_u(u32::MAX);
658        let zero = self.lit_u(0);
659        self.select(cond, ones, zero)
660    }
661
662    /// Close the function being built as the module's function `name` with these arguments and result, and start an
663    /// empty one: a program of a stage with no entry point is several of them (see [`crate::stage_functions`]).
664    pub fn end_function(&mut self, name: &str, decl: FunctionDecl) -> Result<Handle<naga::Function>, String> {
665        self.finishable()?;
666        let mut function = std::mem::take(&mut self.function);
667        function.name = Some(name.to_owned());
668        function.arguments = decl.arguments;
669        function.result = decl.result.map(|ty| naga::FunctionResult { ty, binding: None });
670        function.body = self.blocks.first_mut().map(std::mem::take).unwrap_or_default();
671        Ok(self.module.functions.append(function, Span::UNDEFINED))
672    }
673
674    /// Declare a function with no body, the module's name for an operation the pipeline does (see [`crate::rt`]); one
675    /// that returns a value returns `false`.
676    pub fn declare_operation(
677        &mut self,
678        name: &str,
679        arguments: Vec<naga::FunctionArgument>,
680        returns_bool: bool,
681    ) -> Handle<naga::Function> {
682        let mut function = Function {
683            name: Some(name.to_owned()),
684            arguments,
685            ..Function::default()
686        };
687        if returns_bool {
688            let ty = self.ty_of(Kind::B, Width::One);
689            function.result = Some(naga::FunctionResult { ty, binding: None });
690            let value = function
691                .expressions
692                .append(Expression::Literal(naga::Literal::Bool(false)), Span::UNDEFINED);
693            function
694                .body
695                .push(Statement::Return { value: Some(value) }, Span::UNDEFINED);
696        }
697        self.module.functions.append(function, Span::UNDEFINED)
698    }
699
700    /// Finish a module that has functions and no entry point; an error where the builder cannot be finished (a fault
701    /// nobody checked, control flow left open).
702    pub fn finish_functions(mut self) -> Result<Module, String> {
703        self.finishable()?;
704        Ok(self.module)
705    }
706
707    /// Finish a module whose one entry point `name` runs in `stage` with these `arguments` and `result`;
708    /// `early_depth_test` forces early depth testing. The entry's workgroup size is [`Builder::workgroup_size`]. An
709    /// error where the builder cannot be finished: a fault nobody checked ([`Builder::check`]) or control flow left open,
710    /// both a lifter's own bugs.
711    pub fn finish(
712        mut self,
713        name: &str,
714        stage: naga::ShaderStage,
715        arguments: Vec<naga::FunctionArgument>,
716        result: Option<Handle<Type>>,
717        early_depth_test: bool,
718    ) -> Result<Module, String> {
719        self.finishable()?;
720        let mut function = self.function;
721        function.name = Some(name.to_owned());
722        function.arguments = arguments;
723        function.result = result.map(|ty| naga::FunctionResult { ty, binding: None });
724        function.body = self.blocks.pop().unwrap_or_default();
725        self.module.entry_points.push(naga::EntryPoint {
726            name: name.to_owned(),
727            stage,
728            early_depth_test: early_depth_test.then_some(naga::EarlyDepthTest::Force),
729            workgroup_size: self.workgroup_size,
730            workgroup_size_overrides: None,
731            function,
732            mesh_info: None,
733            task_payload: None,
734            incoming_ray_payload: None,
735        });
736        Ok(self.module)
737    }
738}