ai.onnx.BitwiseAnd / build /webgpu /bitwise-binary-broadcast.wgsl.jinja
Xenova's picture
Xenova HF Staff
sync 91d990483a17
a79717a verified
Raw
History Blame
3.96 kB
{% macro flat_tail_open() %}
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
// 2D-folded flat index: gid.y carries the high bits when the element count exceeds the
// dispatch's per-axis workgroup fold width (the dispatch caps x and spills the rest into y).
let invocation = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ tunables.WORKGROUP_SIZE }}u;
// Tail-safe scalar x4 keeps vector-like dispatch density without requiring
// the logical tensor length (or its storage binding) to be vec4 aligned.
{% set itemsPerInvocation = itemsPerInvocation if itemsPerInvocation is defined else 4 %}
let begin = invocation * {{ itemsPerInvocation }}u;
let end = min(begin + {{ itemsPerInvocation }}u, params.count);
for (var i = begin; i < end; i = i + 1u) {
{%- endmacro %}
{% macro flat_tail_close() %}
}
{% endmacro %}
{% macro offset_fn(fn_name, opShape, opRank, op_same, op_numel, outShape, outRank, out_numel) %}
fn {{ fn_name }}({% if out_numel != 0 and op_numel != 1 %}out_index: u32{% endif %}) -> u32 {
{% if out_numel == 0 %}
return 0u;
{% elif op_numel == 1 %}
return 0u;
{% elif op_same %}
return out_index;
{% else %}
var offset = 0u;
{% for axis in range(outRank) %}
{% set op_axis = axis - (outRank - opRank) %}
{% if op_axis >= 0 and opShape[op_axis] != 1 %}
{% set c_stride = namespace(value=1) %}
{% for j in range(axis + 1, outRank) %}
{% set c_stride.value = c_stride.value * outShape[j] %}
{% endfor %}
{% set op_stride = namespace(value=1) %}
{% for j in range(op_axis + 1, opRank) %}
{% set op_stride.value = op_stride.value * opShape[j] %}
{% endfor %}
{% if c_stride.value == 1 %}
let coord{{ axis }} = out_index % {{ outShape[axis] }}u;
{% else %}
let coord{{ axis }} = (out_index / {{ c_stride.value }}u) % {{ outShape[axis] }}u;
{% endif %}
{% if op_stride.value == 1 %}
offset = offset + coord{{ axis }};
{% else %}
offset = offset + coord{{ axis }} * {{ op_stride.value }}u;
{% endif %}
{% endif %}
{% endfor %}
return offset;
{% endif %}
}
{%- endmacro %}{% macro broadcast_offset_call(fn_name, opShape, outShape, out_index) %}
{% set op_numel = namespace(value=1) %}
{% for d in opShape %}{% set op_numel.value = op_numel.value * d %}{% endfor %}
{% set out_numel = namespace(value=1) %}
{% for d in outShape %}{% set out_numel.value = out_numel.value * d %}{% endfor %}
{{ fn_name }}({% if out_numel.value != 0 and op_numel.value != 1 %}{{ out_index }}{% endif %})
{%- endmacro %}{% macro broadcast_offset_fn(fn_name, opShape, opRank, outShape, outRank) %}
{% set op_numel = namespace(value=1) %}
{% for d in opShape %}
{% set op_numel.value = op_numel.value * d %}
{% endfor %}
{% set out_numel = namespace(value=1) %}
{% for d in outShape %}
{% set out_numel.value = out_numel.value * d %}
{% endfor %}
{% set op_same = namespace(value=(opRank == outRank)) %}
{% if op_same.value %}
{% for axis in range(outRank) %}
{% if opShape[axis] != outShape[axis] %}
{% set op_same.value = false %}
{% endif %}
{% endfor %}
{% endif %}
{{ offset_fn(fn_name, opShape, opRank, op_same.value, op_numel.value, outShape, outRank, out_numel.value) }}
{%- endmacro %}{% macro binary_broadcast_offsets() %}
{% set aShape = aShape | default([]) %}
{% set aRank = aRank | default(0) %}
{% set bShape = bShape | default([]) %}
{% set bRank = bRank | default(0) %}
{% set cShape = cShape | default([]) %}
{% set cRank = cRank | default(0) %}
{{ broadcast_offset_fn("a_offset", aShape, aRank, cShape, cRank) }}
{{ broadcast_offset_fn("b_offset", bShape, bRank, cShape, cRank) }}
{%- endmacro %}
{{ env.wgsl.resourceDeclarations }}
{{ binary_broadcast_offsets() }}
{{ flat_tail_open() }}
var value = a[{{ broadcast_offset_call("a_offset", aShape, cShape, "i") }}] & b[{{ broadcast_offset_call("b_offset", bShape, cShape, "i") }}];
{% if logicalDtype == "uint8" %}
value = value & 0xffu;
{% endif %}
c[i] = value;
{{ flat_tail_close() -}}
}