in src/webgpu/shader/execution/expression/expression.ts [818:909]
export function compoundAssignmentBuilder(op: string): ShaderBuilder {
return (params: ShaderBuilderParams) => {
const { parameterTypes, resultType, cases, inputSource } = params;
//////////////////////////////////////////////////////////////////////////
// Input validation
//////////////////////////////////////////////////////////////////////////
if (parameterTypes.length !== 2) {
throw new Error(`compoundBinaryOp() requires exactly two parameters values per case`);
}
const lhsType = parameterTypes[0];
const rhsType = parameterTypes[1];
if (!objectEquals(lhsType, resultType)) {
throw new Error(
`compoundBinaryOp() requires result type (${resultType}) to be equal to the LHS type (${lhsType})`
);
}
if (inputSource === 'const') {
//////////////////////////////////////////////////////////////////////////
// Constant eval
//////////////////////////////////////////////////////////////////////////
let body = '';
if (globalTestConfig.unrollConstEvalLoops) {
body = cases
.map((_, i) => {
return `
var ret_${i} = lhs[${i}];
ret_${i} ${op} rhs[${i}];
outputs[${i}].value = ${storageType(resultType)}(ret_${i});`;
})
.join('\n ');
} else {
body = `
for (var i = 0u; i < ${cases.length}; i++) {
var ret = lhs[i];
ret ${op} rhs[i];
outputs[i].value = ${storageType(resultType)}(ret);
}`;
}
const values = cases.map(c => (c.input as Value[]).map(v => v.wgsl()));
return `
${wgslHeader(parameterTypes, resultType)}
${wgslOutputs(resultType, cases.length)}
const lhs = array(
${values.map(c => `${c[0]}`).join(',\n ')}
);
const rhs = array(
${values.map(c => `${c[1]}`).join(',\n ')}
);
@compute @workgroup_size(1)
fn main() {
${body}
}`;
} else {
//////////////////////////////////////////////////////////////////////////
// Runtime eval
//////////////////////////////////////////////////////////////////////////
let operation = '';
if (inputSource === 'storage_rw' && objectEquals(resultType, storageType(resultType))) {
operation = `
outputs[i].value = ${storageType(resultType)}(inputs[i].lhs);
outputs[i].value ${op} ${rhsType}(inputs[i].rhs);`;
} else {
operation = `
var ret = ${lhsType}(inputs[i].lhs);
ret ${op} ${rhsType}(inputs[i].rhs);
outputs[i].value = ${storageType(resultType)}(ret);`;
}
return `
${wgslHeader(parameterTypes, resultType)}
${wgslOutputs(resultType, cases.length)}
struct Input {
${wgslMembers([lhsType, rhsType].map(storageType), inputSource, i => ['lhs', 'rhs'][i])}
}
${wgslInputVar(inputSource, cases.length)}
@compute @workgroup_size(1)
fn main() {
for (var i = 0; i < ${cases.length}; i++) {
${operation}
}
}
`;
}
};
}