vyre 0.4.0

GPU compute intermediate representation with a standard operation library
Documentation
struct Params {
    node_count: u32,
    entry: u32,
    max_iterations: u32,
};

@group(0) @binding(0) var<storage, read> successor_offsets: array<u32>;
@group(0) @binding(1) var<storage, read> successors: array<u32>;
@group(0) @binding(2) var<storage, read> predecessor_offsets: array<u32>;
@group(0) @binding(3) var<storage, read> predecessors: array<u32>;
@group(0) @binding(4) var<storage, read_write> idom: array<atomic<u32>>;
@group(0) @binding(5) var<storage, read_write> status: array<atomic<u32>>;
@group(0) @binding(6) var<uniform> params: Params;

var<workgroup> changed: atomic<u32>;

fn intersect(mut_a: u32, mut_b: u32) -> u32 {
    var a = mut_a;
    var b = mut_b;
    loop {
        if (a == b) { return a; }
        if (a > b) {
            a = atomicLoad(&idom[a]);
        } else {
            b = atomicLoad(&idom[b]);
        }
    }
}

@compute @workgroup_size(64)
fn compiler_primitives_dominator_tree(
    @builtin(local_invocation_id) lid: vec3<u32>,
    @builtin(global_invocation_id) gid: vec3<u32>
) {
    let node = gid.x;
    if (node < params.node_count) {
        if (node == params.entry) {
            atomicStore(&idom[node], node);
        } else {
            atomicStore(&idom[node], 0xffffffffu);
        }
    }
    workgroupBarrier();

    var iteration = 0u;
    loop {
        if (iteration >= params.max_iterations) {
            if (lid.x == 0u) { atomicStore(&status[0], 1u); }
            return;
        }
        if (lid.x == 0u) { atomicStore(&changed, 0u); }
        workgroupBarrier();

        if (node < params.node_count && node != params.entry) {
            var new_idom = 0xffffffffu;
            var p = predecessor_offsets[node];
            let pend = predecessor_offsets[node + 1u];
            loop {
                if (p >= pend) { break; }
                let pred = predecessors[p];
                if (atomicLoad(&idom[pred]) != 0xffffffffu) {
                    if (new_idom == 0xffffffffu) {
                        new_idom = pred;
                    } else {
                        new_idom = intersect(pred, new_idom);
                    }
                }
                p = p + 1u;
            }
            if (new_idom != atomicLoad(&idom[node])) {
                atomicStore(&idom[node], new_idom);
                atomicStore(&changed, 1u);
            }
        }
        workgroupBarrier();
        iteration = iteration + 1u;
        if (atomicLoad(&changed) == 0u) {
            if (lid.x == 0u) { atomicStore(&status[0], iteration); }
            return;
        }
    }
}