| export const description = ` |
| Execution tests for operator precedence. |
| `; |
| |
| import { makeTestGroup } from '../../../../common/framework/test_group.js'; |
| import { keysOf } from '../../../../common/util/data_tables.js'; |
| import { GPUTest } from '../../../gpu_test.js'; |
| |
| export const g = makeTestGroup(GPUTest); |
| |
| // The list of test cases and their expected results. |
| interface Expression { |
| expr: string; |
| result: number; |
| } |
| const kExpressions: Record<string, Expression> = { |
| add_mul: { expr: 'kThree + kSeven * kEleven', result: 80 }, |
| mul_add: { expr: 'kThree * kSeven + kEleven', result: 32 }, |
| sub_neg: { expr: 'kThree - - kSeven', result: 10 }, |
| neg_shl: { expr: '- kThree << u32(kSeven)', result: -384 }, |
| neg_shr: { expr: '- kThree >> u32(kSeven)', result: -1 }, |
| neg_add: { expr: '- kThree + kSeven', result: 4 }, |
| neg_mul: { expr: '- kThree * kSeven', result: -21 }, |
| neg_and: { expr: '- kThree & kSeven', result: 5 }, |
| neg_or: { expr: '- kThree | kSeven', result: -1 }, |
| neg_xor: { expr: '- kThree ^ kSeven', result: -6 }, |
| comp_add: { expr: '~ kThree + kSeven', result: 3 }, |
| mul_deref: { expr: 'kThree * * ptr_five', result: 15 }, |
| not_and: { expr: 'i32(! kFalse && kFalse)', result: 0 }, |
| not_or: { expr: 'i32(! kTrue || kTrue)', result: 1 }, |
| eq_and: { expr: 'i32(kFalse == kTrue && kFalse)', result: 0 }, |
| and_eq: { expr: 'i32(kFalse && kTrue == kFalse)', result: 0 }, |
| eq_or: { expr: 'i32(kFalse == kFalse || kTrue)', result: 1 }, |
| or_eq: { expr: 'i32(kTrue || kFalse == kFalse)', result: 1 }, |
| add_swizzle: { expr: '(vec + vec . y) . z', result: 8 }, |
| }; |
| |
| g.test('precedence') |
| .desc( |
| ` |
| Test that operator precedence rules are correctly implemented. |
| ` |
| ) |
| .params(u => |
| u |
| .combine('expr', keysOf(kExpressions)) |
| .combine('decl', ['literal', 'const', 'override', 'var<private>']) |
| .combine('strip_spaces', [false, true]) |
| ) |
| .fn(t => { |
| const expr = kExpressions[t.params.expr]; |
| |
| let decl = t.params.decl; |
| let expr_wgsl = expr.expr; |
| if (t.params.decl === 'literal') { |
| decl = 'const'; |
| expr_wgsl = expr_wgsl.replace(/kThree/g, '3'); |
| expr_wgsl = expr_wgsl.replace(/kSeven/g, '7'); |
| expr_wgsl = expr_wgsl.replace(/kEleven/g, '11'); |
| expr_wgsl = expr_wgsl.replace(/kFalse/g, 'false'); |
| expr_wgsl = expr_wgsl.replace(/kTrue/g, 'true'); |
| } |
| if (t.params.strip_spaces) { |
| expr_wgsl = expr_wgsl.replace(/ /g, ''); |
| } |
| const wgsl = ` |
| @group(0) @binding(0) var<storage, read_write> buffer : i32; |
| |
| ${decl} kFalse = false; |
| ${decl} kTrue = true; |
| |
| ${decl} kThree = 3; |
| ${decl} kSeven = 7; |
| ${decl} kEleven = 11; |
| |
| @compute @workgroup_size(1) |
| fn main() { |
| var five = 5; |
| var vec = vec4(1, kThree, 5, kSeven); |
| let ptr_five = &five; |
| |
| buffer = ${expr_wgsl}; |
| } |
| `; |
| const pipeline = t.device.createComputePipeline({ |
| layout: 'auto', |
| compute: { |
| module: t.device.createShaderModule({ code: wgsl }), |
| }, |
| }); |
| |
| // Allocate a buffer and fill it with 0xdeadbeef. |
| const outputBuffer = t.makeBufferWithContents( |
| new Uint32Array([0xdeadbeef]), |
| GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC |
| ); |
| const bindGroup = t.device.createBindGroup({ |
| layout: pipeline.getBindGroupLayout(0), |
| entries: [{ binding: 0, resource: { buffer: outputBuffer } }], |
| }); |
| |
| // Run the shader. |
| const encoder = t.device.createCommandEncoder(); |
| const pass = encoder.beginComputePass(); |
| pass.setPipeline(pipeline); |
| pass.setBindGroup(0, bindGroup); |
| pass.dispatchWorkgroups(1); |
| pass.end(); |
| t.queue.submit([encoder.finish()]); |
| |
| // Check that the result is as expected. |
| t.expectGPUBufferValuesEqual(outputBuffer, new Int32Array([expr.result])); |
| }); |