Control flow

Control flow

A loop has to be one the GPU can finish, and a choice between two values has to be one the target has an operator for.

  • if

    An if, as written.

    TypeScript
    export function capped(x: f32): f32 {
    if (x > 1.) {
    return 1.
    }
    return x
    }
    Emitted WGSL
    fn capped(x: f32) -> f32 {
    if ((x > 1.0)) {
    return 1.0;
    }
    return x;
    }
  • Counted for

    A counted loop: an integer variable, a constant step, and an exit that compares it to a bound the body does not write. block-scope

    TypeScript
    export function ramp(x: f32): f32 {
    let acc: f32 = 0.
    for (let i = 0; i < 4; i += 1) {
    acc = acc + x * f32(i)
    }
    return acc
    }
    Emitted WGSL
    fn ramp(x: f32) -> f32 {
    var acc: f32 = 0.0;
    for (var i: i32 = 0; (i < 4); i += 1) {
    acc = (acc + (x * f32(i)));
    }
    return acc;
    }
  • for to a runtime bound

    The start and the bound may be values the program learns at run time, and no trip count is too many.

    TypeScript
    export function ramp(x: f32, n: i32): f32 {
    let acc: f32 = 0.
    for (let i = 0; i < n; i += 1) {
    acc = acc + x
    }
    return acc
    }
    Emitted WGSL
    fn ramp(x: f32, n: i32) -> f32 {
    var acc: f32 = 0.0;
    for (var i: i32 = 0; (i < n); i += 1) {
    acc = (acc + x);
    }
    return acc;
    }
  • while

    A loop with a counter the compiler adds. Nothing checks that the body moves toward the bound.

    TypeScript
    export function halve(x: f32): f32 {
    let acc: f32 = x
    let w: i32 = 0
    while (w < 4) {
    acc = acc * 0.5
    w = w + 1
    }
    return acc
    }
    Emitted WGSL
    fn halve(x: f32) -> f32 {
    var acc: f32 = x;
    var w: i32 = 0;
    for (var _w: i32 = 0; (w < 4); _w = (_w + 1)) {
    acc = (acc * 0.5);
    w = (w + 1);
    }
    return acc;
    }
  • switch

    A switch. Each case ends with a break, which the lowering drops. A case whose end is reachable is refused (TS8017), because TypeScript would run on into the next case and WGSL runs only the one. bitfield-bands

    TypeScript
    export function band(m: i32): f32 {
    let v: f32 = 0.
    switch (m) {
    case 0:
    v = 0.25
    break
    default:
    v = 1.
    break
    }
    return v
    }
    Emitted WGSL
    fn band(m: i32) -> f32 {
    var v: f32 = 0.0;
    switch m {
    case 0: {
    v = 0.25;
    }
    default: {
    v = 1.0;
    }
    }
    return v;
    }
  • Ternary on a scalar

    A select on WGSL, and the ternary each GLSL ES 3.00 driver has.

    TypeScript
    export function nearer(a: f32, b: f32): f32 {
    return a < b ? a : b
    }
    Emitted WGSL
    fn nearer(a: f32, b: f32) -> f32 {
    return select(b, a, (a < b));
    }
  • Ternary on a struct

    Neither target has an operator for it, so the value is hoisted into a slot and an if. pick-composite

    TypeScript
    export function chosen(
    warm: Palette, cool: Palette, c: bool
    ): vec3 {
    const shade: Palette = c ? warm : cool
    return shade.lo
    }
    Emitted WGSL
    fn chosen(warm: Palette, cool: Palette, c: bool) -> vec3<f32> {
    var _sel0: Palette;
    if (c) {
    _sel0 = warm;
    } else {
    _sel0 = cool;
    }
    let shade = _sel0;
    return shade.lo;
    }
  • break

    A break, which is how a counted loop leaves early. julia-twin

    TypeScript
    export function escape(x: f32): f32 {
    let acc: f32 = x
    for (let i = 0; i < 8; i += 1) {
    acc = acc * 2.
    if (acc > 1.) {
    break
    }
    }
    return acc
    }
    Emitted WGSL
    fn escape(x: f32) -> f32 {
    var acc: f32 = x;
    for (var i: i32 = 0; (i < 8); i += 1) {
    acc = (acc * 2.0);
    if ((acc > 1.0)) {
    break;
    }
    }
    return acc;
    }
  • continue

    A continue. In a switch that no loop encloses it is refused.

    TypeScript
    export function odds(x: f32): f32 {
    let acc: f32 = 0.
    for (let i = 0; i < 4; i += 1) {
    if (i === 2) {
    continue
    }
    acc = acc + x
    }
    return acc
    }
    Emitted WGSL
    fn odds(x: f32) -> f32 {
    var acc: f32 = 0.0;
    for (var i: i32 = 0; (i < 4); i += 1) {
    if ((i == 2)) {
    continue;
    }
    acc = (acc + x);
    }
    return acc;
    }
  • discard

    A discard, in a fragment entry or in a function one calls. cutout

    TypeScript
    @fragment
    export function fs(
    @builtin("position") frag: vec4
    ): vec4 {
    if (frag.x < 0.5) {
    discard
    }
    return vec4(1.)
    }
    Emitted WGSL
    @fragment
    fn fs(@builtin(position) frag: vec4<f32>) -> @location(0) vec4<f32> {
    if ((frag.x < 0.5)) {
    discard;
    }
    return vec4<f32>(1.0, 1.0, 1.0, 1.0);
    }

Edit this page Report a problem