diff --git a/src/webgpu/listing_meta.json b/src/webgpu/listing_meta.json index 0e31402151ef..003cc21dfb5d 100644 --- a/src/webgpu/listing_meta.json +++ b/src/webgpu/listing_meta.json @@ -1226,6 +1226,8 @@ "webgpu:shader,execution,expression,call,builtin,dot:f32_vec4:*": { "subcaseMS": 11.876 }, "webgpu:shader,execution,expression,call,builtin,dot:i32:*": { "subcaseMS": 3.103 }, "webgpu:shader,execution,expression,call,builtin,dot:u32:*": { "subcaseMS": 3.101 }, + "webgpu:shader,execution,expression,call,builtin,dot4I8Packed:basic:*": { "subcaseMS": 1.000 }, + "webgpu:shader,execution,expression,call,builtin,dot4U8Packed:basic:*": { "subcaseMS": 1.000 }, "webgpu:shader,execution,expression,call,builtin,dpdx:f32:*": { "subcaseMS": 22.804 }, "webgpu:shader,execution,expression,call,builtin,dpdxCoarse:f32:*": { "subcaseMS": 22.404 }, "webgpu:shader,execution,expression,call,builtin,dpdxFine:f32:*": { "subcaseMS": 17.708 }, diff --git a/src/webgpu/shader/execution/expression/call/builtin/dot4I8Packed.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/dot4I8Packed.spec.ts new file mode 100644 index 000000000000..dee5290281a8 --- /dev/null +++ b/src/webgpu/shader/execution/expression/call/builtin/dot4I8Packed.spec.ts @@ -0,0 +1,74 @@ +export const description = ` +Execution tests for the 'dot4I8Packed' builtin function + +@const fn dot4I8Packed(e1: u32 ,e2: u32) -> i32 +e1 and e2 are interpreted as vectors with four 8-bit signed integer components. Return the signed +integer dot product of these two vectors. Each component is sign-extended to i32 before performing +the multiply, and then the add operations are done in WGSL i32 with wrapping behaviour. +`; + +import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../../gpu_test.js'; +import { TypeI32, TypeU32, i32, u32 } from '../../../../../util/conversion.js'; +import { Case } from '../../case.js'; +import { allInputSources, Config, run } from '../../expression.js'; + +import { builtin } from './builtin.js'; + +export const g = makeTestGroup(GPUTest); + +g.test('basic') + .specURL('https://www.w3.org/TR/WGSL/#dot4I8Packed-builtin') + .desc( + ` +@const fn dot4I8Packed(e1: u32, e2: u32) -> i32 + ` + ) + .params(u => u.combine('inputSource', allInputSources)) + .fn(async t => { + const cfg: Config = t.params; + + const dot4I8Packed = (e1: number, e2: number) => { + let result = 0; + for (let i = 0; i < 4; ++i) { + let e1_i = (e1 >> (i * 8)) & 0xff; + if (e1_i >= 128) { + e1_i -= 256; + } + let e2_i = (e2 >> (i * 8)) & 0xff; + if (e2_i >= 128) { + e2_i -= 256; + } + result += e1_i * e2_i; + } + return result; + }; + + const testInputs = [ + // dot({0, 0, 0, 0}, {0, 0, 0, 0}) + [0, 0], + // dot({127, 127, 127, 127}, {127, 127, 127, 127}) + [0x7f7f7f7f, 0x7f7f7f7f], + // dot({-128, -128, -128, -128}, {-128, -128, -128, -128}) + [0x80808080, 0x80808080], + // dot({127, 127, 127, 127}, {-128, -128, -128, -128}) + [0x7f7f7f7f, 0x80808080], + // dot({1, 2, 3, 4}, {5, 6, 7, 8}) + [0x01020304, 0x05060708], + // dot({1, 2, 3, 4}, {-1, -2, -3, -4}) + [0x01020304, 0xfffefdfc], + // dot({-5, -6, -7, -8}, {5, 6, 7, 8}) + [0xfbfaf9f8, 0x05060708], + // dot({-9, -10, -11, -12}, {-13, -14, -15, -16}) + [0xf7f6f5f4, 0xf3f2f1f0], + ] as const; + + const makeCase = (x: number, y: number): Case => { + return { input: [u32(x), u32(y)], expected: i32(dot4I8Packed(x, y)) }; + }; + const cases: Array = testInputs.flatMap(v => { + return [makeCase(...(v as [number, number]))]; + }); + + await run(t, builtin('dot4I8Packed'), [TypeU32, TypeU32], TypeI32, cfg, cases); + }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/dot4U8Packed.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/dot4U8Packed.spec.ts new file mode 100644 index 000000000000..f0dd6fc5081b --- /dev/null +++ b/src/webgpu/shader/execution/expression/call/builtin/dot4U8Packed.spec.ts @@ -0,0 +1,59 @@ +export const description = ` +Execution tests for the 'dot4U8Packed' builtin function + +@const fn dot4U8Packed(e1: u32 ,e2: u32) -> u32 +e1 and e2 are interpreted as vectors with four 8-bit unsigned integer components. Return the +unsigned integer dot product of these two vectors. +`; + +import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../../gpu_test.js'; +import { TypeU32, u32 } from '../../../../../util/conversion.js'; +import { Case } from '../../case.js'; +import { allInputSources, Config, run } from '../../expression.js'; + +import { builtin } from './builtin.js'; + +export const g = makeTestGroup(GPUTest); + +g.test('basic') + .specURL('https://www.w3.org/TR/WGSL/#dot4U8Packed-builtin') + .desc( + ` +@const fn dot4U8Packed(e1: u32, e2: u32) -> u32 + ` + ) + .params(u => u.combine('inputSource', allInputSources)) + .fn(async t => { + const cfg: Config = t.params; + + const dot4U8Packed = (e1: number, e2: number) => { + let result = 0; + for (let i = 0; i < 4; ++i) { + const e1_i = (e1 >> (i * 8)) & 0xff; + const e2_i = (e2 >> (i * 8)) & 0xff; + result += e1_i * e2_i; + } + return result; + }; + + const testInputs = [ + // dot({0, 0, 0, 0}, {0, 0, 0, 0}) + [0, 0], + // dot({255u, 255u, 255u, 255u}, {255u, 255u, 255u, 255u}) + [0xffffffff, 0xffffffff], + // dot({1u, 2u, 3u, 4u}, {5u, 6u, 7u, 8u}) + [0x01020304, 0x05060708], + // dot({120u, 90u, 60u, 30u}, {50u, 100u, 150u, 200u}) + [0x785a3c1e, 0x326496c8], + ] as const; + + const makeCase = (x: number, y: number): Case => { + return { input: [u32(x), u32(y)], expected: u32(dot4U8Packed(x, y)) }; + }; + const cases: Array = testInputs.flatMap(v => { + return [makeCase(...(v as [number, number]))]; + }); + + await run(t, builtin('dot4U8Packed'), [TypeU32, TypeU32], TypeU32, cfg, cases); + });