diff options
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary')
7 files changed, 1195 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/binary.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/binary.ts new file mode 100644 index 0000000000..dcfc2b2a3f --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/binary.ts @@ -0,0 +1,9 @@ +import { ExpressionBuilder } from '../expression.js'; + +/* @returns an ExpressionBuilder that evaluates a binary operation */ +export function binary(op: string): ExpressionBuilder { + return values => { + const values_str = values.map(v => `(${v})`); + return `(${values_str.join(op)})`; + }; +} diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/bitwise.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/bitwise.spec.ts new file mode 100644 index 0000000000..6a708564d9 --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/bitwise.spec.ts @@ -0,0 +1,220 @@ +export const description = ` +Execution Tests for the bitwise binary expression operations +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../gpu_test.js'; +import { i32, scalarType, u32 } from '../../../../util/conversion.js'; +import { allInputSources, run } from '../expression.js'; + +import { binary } from './binary.js'; + +export const g = makeTestGroup(GPUTest); + +g.test('bitwise_or') + .specURL('https://www.w3.org/TR/WGSL/#bit-expr') + .desc( + ` +e1 | e2: T +T is i32, u32, vecN<i32>, or vecN<u32> + +Bitwise-or. Component-wise when T is a vector. +` + ) + .params(u => + u + .combine('type', ['i32', 'u32'] as const) + .combine('inputSource', allInputSources) + .combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const type = scalarType(t.params.type); + const V = t.params.type === 'i32' ? i32 : u32; + const cases = [ + // Static patterns + { + input: [V(0b00000000000000000000000000000000), V(0b00000000000000000000000000000000)], + expected: V(0b00000000000000000000000000000000), + }, + { + input: [V(0b11111111111111111111111111111111), V(0b00000000000000000000000000000000)], + expected: V(0b11111111111111111111111111111111), + }, + { + input: [V(0b00000000000000000000000000000000), V(0b11111111111111111111111111111111)], + expected: V(0b11111111111111111111111111111111), + }, + { + input: [V(0b11111111111111111111111111111111), V(0b11111111111111111111111111111111)], + expected: V(0b11111111111111111111111111111111), + }, + { + input: [V(0b10100100010010100100010010100100), V(0b00000000000000000000000000000000)], + expected: V(0b10100100010010100100010010100100), + }, + { + input: [V(0b00000000000000000000000000000000), V(0b10100100010010100100010010100100)], + expected: V(0b10100100010010100100010010100100), + }, + { + input: [V(0b01010010001001010010001001010010), V(0b10100100010010100100010010100100)], + expected: V(0b11110110011011110110011011110110), + }, + ]; + // Permute all combinations of a single bit being set for the LHS and RHS + for (let i = 0; i < 32; i++) { + const lhs = 1 << i; + for (let j = 0; j < 32; j++) { + const rhs = 1 << j; + cases.push({ + input: [V(lhs), V(rhs)], + expected: V(lhs | rhs), + }); + } + } + await run(t, binary('|'), [type, type], type, t.params, cases); + }); + +g.test('bitwise_and') + .specURL('https://www.w3.org/TR/WGSL/#bit-expr') + .desc( + ` +e1 & e2: T +T is i32, u32, vecN<i32>, or vecN<u32> + +Bitwise-and. Component-wise when T is a vector. +` + ) + .params(u => + u + .combine('type', ['i32', 'u32'] as const) + .combine('inputSource', allInputSources) + .combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const type = scalarType(t.params.type); + const V = t.params.type === 'i32' ? i32 : u32; + const cases = [ + // Static patterns + { + input: [V(0b00000000000000000000000000000000), V(0b00000000000000000000000000000000)], + expected: V(0b00000000000000000000000000000000), + }, + { + input: [V(0b11111111111111111111111111111111), V(0b00000000000000000000000000000000)], + expected: V(0b00000000000000000000000000000000), + }, + { + input: [V(0b00000000000000000000000000000000), V(0b11111111111111111111111111111111)], + expected: V(0b00000000000000000000000000000000), + }, + { + input: [V(0b11111111111111111111111111111111), V(0b11111111111111111111111111111111)], + expected: V(0b11111111111111111111111111111111), + }, + { + input: [V(0b10100100010010100100010010100100), V(0b00000000000000000000000000000000)], + expected: V(0b00000000000000000000000000000000), + }, + { + input: [V(0b10100100010010100100010010100100), V(0b11111111111111111111111111111111)], + expected: V(0b10100100010010100100010010100100), + }, + { + input: [V(0b00000000000000000000000000000000), V(0b10100100010010100100010010100100)], + expected: V(0b00000000000000000000000000000000), + }, + { + input: [V(0b11111111111111111111111111111111), V(0b10100100010010100100010010100100)], + expected: V(0b10100100010010100100010010100100), + }, + { + input: [V(0b01010010001001010010001001010010), V(0b01011011101101011011101101011011)], + expected: V(0b01010010001001010010001001010010), + }, + ]; + // Permute all combinations of a single bit being set for the LHS and all but one bit set for the RHS + for (let i = 0; i < 32; i++) { + const lhs = 1 << i; + for (let j = 0; j < 32; j++) { + const rhs = 0xffffffff ^ (1 << j); + cases.push({ + input: [V(lhs), V(rhs)], + expected: V(lhs & rhs), + }); + } + } + await run(t, binary('&'), [type, type], type, t.params, cases); + }); + +g.test('bitwise_exclusive_or') + .specURL('https://www.w3.org/TR/WGSL/#bit-expr') + .desc( + ` +e1 ^ e2: T +T is i32, u32, vecN<i32>, or vecN<u32> + +Bitwise-exclusive-or. Component-wise when T is a vector. +` + ) + .params(u => + u + .combine('type', ['i32', 'u32'] as const) + .combine('inputSource', allInputSources) + .combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const type = scalarType(t.params.type); + const V = t.params.type === 'i32' ? i32 : u32; + const cases = [ + // Static patterns + { + input: [V(0b00000000000000000000000000000000), V(0b00000000000000000000000000000000)], + expected: V(0b00000000000000000000000000000000), + }, + { + input: [V(0b11111111111111111111111111111111), V(0b00000000000000000000000000000000)], + expected: V(0b11111111111111111111111111111111), + }, + { + input: [V(0b00000000000000000000000000000000), V(0b11111111111111111111111111111111)], + expected: V(0b11111111111111111111111111111111), + }, + { + input: [V(0b11111111111111111111111111111111), V(0b11111111111111111111111111111111)], + expected: V(0b00000000000000000000000000000000), + }, + { + input: [V(0b10100100010010100100010010100100), V(0b00000000000000000000000000000000)], + expected: V(0b10100100010010100100010010100100), + }, + { + input: [V(0b10100100010010100100010010100100), V(0b11111111111111111111111111111111)], + expected: V(0b01011011101101011011101101011011), + }, + { + input: [V(0b00000000000000000000000000000000), V(0b10100100010010100100010010100100)], + expected: V(0b10100100010010100100010010100100), + }, + { + input: [V(0b11111111111111111111111111111111), V(0b10100100010010100100010010100100)], + expected: V(0b01011011101101011011101101011011), + }, + { + input: [V(0b01010010001001010010001001010010), V(0b01011011101101011011101101011011)], + expected: V(0b00001001100100001001100100001001), + }, + ]; + // Permute all combinations of a single bit being set for the LHS and all but one bit set for the RHS + for (let i = 0; i < 32; i++) { + const lhs = 1 << i; + for (let j = 0; j < 32; j++) { + const rhs = 0xffffffff ^ (1 << j); + cases.push({ + input: [V(lhs), V(rhs)], + expected: V(lhs ^ rhs), + }); + } + } + await run(t, binary('^'), [type, type], type, t.params, cases); + }); diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/bool_logical.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/bool_logical.spec.ts new file mode 100644 index 0000000000..d3c426920a --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/bool_logical.spec.ts @@ -0,0 +1,143 @@ +export const description = ` +Execution Tests for the boolean binary logical expression operations +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../gpu_test.js'; +import { bool, TypeBool } from '../../../../util/conversion.js'; +import { allInputSources, run } from '../expression.js'; + +import { binary } from './binary.js'; + +export const g = makeTestGroup(GPUTest); + +// Short circuiting vs no short circuiting is not tested here, it is covered in +// src/webgpu/shader/execution/evaluation_order.spec.ts + +g.test('and') + .specURL('https://www.w3.org/TR/WGSL/#logical-expr') + .desc( + ` +Expression: e1 & e2 +Logical "and". Component-wise when T is a vector. Evaluates both e1 and e2. +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = [ + { input: [bool(false), bool(false)], expected: bool(false) }, + { input: [bool(true), bool(false)], expected: bool(false) }, + { input: [bool(false), bool(true)], expected: bool(false) }, + { input: [bool(true), bool(true)], expected: bool(true) }, + ]; + + await run(t, binary('&'), [TypeBool, TypeBool], TypeBool, t.params, cases); + }); + +g.test('and_short_circuit') + .specURL('https://www.w3.org/TR/WGSL/#logical-expr') + .desc( + ` +Expression: e1 && e2 +short_circuiting "and". Yields true if both e1 and e2 are true; evaluates e2 only if e1 is true. +` + ) + .params(u => u.combine('inputSource', allInputSources)) + .fn(async t => { + const cases = [ + { input: [bool(false), bool(false)], expected: bool(false) }, + { input: [bool(true), bool(false)], expected: bool(false) }, + { input: [bool(false), bool(true)], expected: bool(false) }, + { input: [bool(true), bool(true)], expected: bool(true) }, + ]; + + await run(t, binary('&&'), [TypeBool, TypeBool], TypeBool, t.params, cases); + }); + +g.test('or') + .specURL('https://www.w3.org/TR/WGSL/#logical-expr') + .desc( + ` +Expression: e1 | e2 +Logical "or". Component-wise when T is a vector. Evaluates both e1 and e2. +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = [ + { input: [bool(false), bool(false)], expected: bool(false) }, + { input: [bool(true), bool(false)], expected: bool(true) }, + { input: [bool(false), bool(true)], expected: bool(true) }, + { input: [bool(true), bool(true)], expected: bool(true) }, + ]; + + await run(t, binary('|'), [TypeBool, TypeBool], TypeBool, t.params, cases); + }); + +g.test('or_short_circuit') + .specURL('https://www.w3.org/TR/WGSL/#logical-expr') + .desc( + ` +Expression: e1 || e2 +short_circuiting "and". Yields true if both e1 and e2 are true; evaluates e2 only if e1 is true. +` + ) + .params(u => u.combine('inputSource', allInputSources)) + .fn(async t => { + const cases = [ + { input: [bool(false), bool(false)], expected: bool(false) }, + { input: [bool(true), bool(false)], expected: bool(true) }, + { input: [bool(false), bool(true)], expected: bool(true) }, + { input: [bool(true), bool(true)], expected: bool(true) }, + ]; + + await run(t, binary('||'), [TypeBool, TypeBool], TypeBool, t.params, cases); + }); + +g.test('equals') + .specURL('https://www.w3.org/TR/WGSL/#logical-expr') + .desc( + ` +Expression: e1 == e2 +Equality. Component-wise when T is a vector. +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = [ + { input: [bool(false), bool(false)], expected: bool(true) }, + { input: [bool(true), bool(false)], expected: bool(false) }, + { input: [bool(false), bool(true)], expected: bool(false) }, + { input: [bool(true), bool(true)], expected: bool(true) }, + ]; + + await run(t, binary('=='), [TypeBool, TypeBool], TypeBool, t.params, cases); + }); + +g.test('not_equals') + .specURL('https://www.w3.org/TR/WGSL/#logical-expr') + .desc( + ` +Expression: e1 != e2 +Equality. Component-wise when T is a vector. +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = [ + { input: [bool(false), bool(false)], expected: bool(false) }, + { input: [bool(true), bool(false)], expected: bool(true) }, + { input: [bool(false), bool(true)], expected: bool(true) }, + { input: [bool(true), bool(true)], expected: bool(false) }, + ]; + + await run(t, binary('!='), [TypeBool, TypeBool], TypeBool, t.params, cases); + }); diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/f32_arithmetic.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/f32_arithmetic.spec.ts new file mode 100644 index 0000000000..84d32191bc --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/f32_arithmetic.spec.ts @@ -0,0 +1,194 @@ +export const description = ` +Execution Tests for the f32 arithmetic binary expression operations +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../gpu_test.js'; +import { TypeF32 } from '../../../../util/conversion.js'; +import { + additionInterval, + divisionInterval, + multiplicationInterval, + remainderInterval, + subtractionInterval, +} from '../../../../util/f32_interval.js'; +import { fullF32Range } from '../../../../util/math.js'; +import { makeCaseCache } from '../case_cache.js'; +import { allInputSources, generateBinaryToF32IntervalCases, run } from '../expression.js'; + +import { binary } from './binary.js'; + +export const g = makeTestGroup(GPUTest); + +export const d = makeCaseCache('binary/f32_arithmetic', { + addition_const: () => { + return generateBinaryToF32IntervalCases( + fullF32Range(), + fullF32Range(), + 'f32-only', + additionInterval + ); + }, + addition_non_const: () => { + return generateBinaryToF32IntervalCases( + fullF32Range(), + fullF32Range(), + 'unfiltered', + additionInterval + ); + }, + subtraction_const: () => { + return generateBinaryToF32IntervalCases( + fullF32Range(), + fullF32Range(), + 'f32-only', + subtractionInterval + ); + }, + subtraction_non_const: () => { + return generateBinaryToF32IntervalCases( + fullF32Range(), + fullF32Range(), + 'unfiltered', + subtractionInterval + ); + }, + multiplication_const: () => { + return generateBinaryToF32IntervalCases( + fullF32Range(), + fullF32Range(), + 'f32-only', + multiplicationInterval + ); + }, + multiplication_non_const: () => { + return generateBinaryToF32IntervalCases( + fullF32Range(), + fullF32Range(), + 'unfiltered', + multiplicationInterval + ); + }, + division_const: () => { + return generateBinaryToF32IntervalCases( + fullF32Range(), + fullF32Range(), + 'f32-only', + divisionInterval + ); + }, + division_non_const: () => { + return generateBinaryToF32IntervalCases( + fullF32Range(), + fullF32Range(), + 'unfiltered', + divisionInterval + ); + }, + remainder_const: () => { + return generateBinaryToF32IntervalCases( + fullF32Range(), + fullF32Range(), + 'f32-only', + remainderInterval + ); + }, + remainder_non_const: () => { + return generateBinaryToF32IntervalCases( + fullF32Range(), + fullF32Range(), + 'unfiltered', + remainderInterval + ); + }, +}); + +g.test('addition') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x + y +Accuracy: Correctly rounded +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'addition_const' : 'addition_non_const' + ); + await run(t, binary('+'), [TypeF32, TypeF32], TypeF32, t.params, cases); + }); + +g.test('subtraction') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x - y +Accuracy: Correctly rounded +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'subtraction_const' : 'subtraction_non_const' + ); + await run(t, binary('-'), [TypeF32, TypeF32], TypeF32, t.params, cases); + }); + +g.test('multiplication') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x * y +Accuracy: Correctly rounded +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'multiplication_const' : 'multiplication_non_const' + ); + await run(t, binary('*'), [TypeF32, TypeF32], TypeF32, t.params, cases); + }); + +g.test('division') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x / y +Accuracy: 2.5 ULP for |y| in the range [2^-126, 2^126] +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'division_const' : 'division_non_const' + ); + await run(t, binary('/'), [TypeF32, TypeF32], TypeF32, t.params, cases); + }); + +g.test('remainder') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x % y +Accuracy: Derived from x - y * trunc(x/y) +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'remainder_const' : 'remainder_non_const' + ); + await run(t, binary('%'), [TypeF32, TypeF32], TypeF32, t.params, cases); + }); diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/f32_logical.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/f32_logical.spec.ts new file mode 100644 index 0000000000..21f2810d01 --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/f32_logical.spec.ts @@ -0,0 +1,260 @@ +export const description = ` +Execution Tests for the f32 logical binary expression operations +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../gpu_test.js'; +import { anyOf } from '../../../../util/compare.js'; +import { bool, f32, Scalar, TypeBool, TypeF32 } from '../../../../util/conversion.js'; +import { flushSubnormalScalarF32, vectorF32Range } from '../../../../util/math.js'; +import { makeCaseCache } from '../case_cache.js'; +import { allInputSources, Case, run } from '../expression.js'; + +import { binary } from './binary.js'; + +export const g = makeTestGroup(GPUTest); + +/** + * @returns a test case for the provided left hand & right hand values and truth function. + * Handles quantization and subnormals. + */ +function makeCase( + lhs: number, + rhs: number, + truthFunc: (lhs: Scalar, rhs: Scalar) => boolean +): Case { + const f32_lhs = f32(lhs); + const f32_rhs = f32(rhs); + const lhs_options = new Set([f32_lhs, flushSubnormalScalarF32(f32_lhs)]); + const rhs_options = new Set([f32_rhs, flushSubnormalScalarF32(f32_rhs)]); + const expected: Array<Scalar> = []; + lhs_options.forEach(l => { + rhs_options.forEach(r => { + const result = bool(truthFunc(l, r)); + if (!expected.includes(result)) { + expected.push(result); + } + }); + }); + + return { input: [f32_lhs, f32_rhs], expected: anyOf(...expected) }; +} + +export const d = makeCaseCache('binary/f32_logical', { + equals_non_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) === (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + equals_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) === (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + not_equals_non_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) !== (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + not_equals_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) !== (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + less_than_non_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) < (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + less_than_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) < (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + less_equals_non_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) <= (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + less_equals_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) <= (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + greater_than_non_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) > (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + greater_than_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) > (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + greater_equals_non_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) >= (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, + greater_equals_const: () => { + const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + return (lhs.value as number) >= (rhs.value as number); + }; + + return vectorF32Range(2).map(v => { + return makeCase(v[0], v[1], truthFunc); + }); + }, +}); + +g.test('equals') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x == y +Accuracy: Correct result +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'equals_const' : 'equals_non_const' + ); + await run(t, binary('=='), [TypeF32, TypeF32], TypeBool, t.params, cases); + }); + +g.test('not_equals') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x != y +Accuracy: Correct result +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'not_equals_const' : 'not_equals_non_const' + ); + await run(t, binary('!='), [TypeF32, TypeF32], TypeBool, t.params, cases); + }); + +g.test('less_than') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x < y +Accuracy: Correct result +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'less_than_const' : 'less_than_non_const' + ); + await run(t, binary('<'), [TypeF32, TypeF32], TypeBool, t.params, cases); + }); + +g.test('less_equals') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x <= y +Accuracy: Correct result +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'less_equals_const' : 'less_equals_non_const' + ); + await run(t, binary('<='), [TypeF32, TypeF32], TypeBool, t.params, cases); + }); + +g.test('greater_than') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x > y +Accuracy: Correct result +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'greater_than_const' : 'greater_than_non_const' + ); + await run(t, binary('>'), [TypeF32, TypeF32], TypeBool, t.params, cases); + }); + +g.test('greater_equals') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x >= y +Accuracy: Correct result +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'greater_equals_const' : 'greater_equals_non_const' + ); + await run(t, binary('>='), [TypeF32, TypeF32], TypeBool, t.params, cases); + }); diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts new file mode 100644 index 0000000000..bbdb260a2d --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts @@ -0,0 +1,156 @@ +export const description = ` +Execution Tests for the i32 arithmetic binary expression operations +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../gpu_test.js'; +import { kValue } from '../../../../util/constants.js'; +import { TypeI32 } from '../../../../util/conversion.js'; +import { fullI32Range } from '../../../../util/math.js'; +import { makeCaseCache } from '../case_cache.js'; +import { allInputSources, generateBinaryToI32Cases, run } from '../expression.js'; + +import { binary } from './binary.js'; + +export const g = makeTestGroup(GPUTest); + +export const d = makeCaseCache('binary/i32_arithmetic', { + addition: () => { + return generateBinaryToI32Cases(fullI32Range(), fullI32Range(), (x, y) => { + return x + y; + }); + }, + subtraction: () => { + return generateBinaryToI32Cases(fullI32Range(), fullI32Range(), (x, y) => { + return x - y; + }); + }, + multiplication: () => { + return generateBinaryToI32Cases(fullI32Range(), fullI32Range(), (x, y) => { + return Math.imul(x, y); + }); + }, + division_non_const: () => { + return generateBinaryToI32Cases(fullI32Range(), fullI32Range(), (x, y) => { + if (y === 0) { + return x; + } + if (x === kValue.i32.negative.min && y === -1) { + return x; + } + return x / y; + }); + }, + division_const: () => { + return generateBinaryToI32Cases(fullI32Range(), fullI32Range(), (x, y) => { + if (y === 0) { + return undefined; + } + if (x === kValue.i32.negative.min && y === -1) { + return undefined; + } + return x / y; + }); + }, + remainder_non_const: () => { + return generateBinaryToI32Cases(fullI32Range(), fullI32Range(), (x, y) => { + if (y === 0) { + return 0; + } + if (x === kValue.i32.negative.min && y === -1) { + return 0; + } + return x % y; + }); + }, + remainder_const: () => { + return generateBinaryToI32Cases(fullI32Range(), fullI32Range(), (x, y) => { + if (y === 0) { + return undefined; + } + if (x === kValue.i32.negative.min && y === -1) { + return undefined; + } + return x % y; + }); + }, +}); + +g.test('addition') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x + y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get('addition'); + await run(t, binary('+'), [TypeI32, TypeI32], TypeI32, t.params, cases); + }); + +g.test('subtraction') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x - y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get('subtraction'); + await run(t, binary('-'), [TypeI32, TypeI32], TypeI32, t.params, cases); + }); + +g.test('multiplication') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x * y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get('multiplication'); + await run(t, binary('*'), [TypeI32, TypeI32], TypeI32, t.params, cases); + }); + +g.test('division') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x / y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'division_const' : 'division_non_const' + ); + await run(t, binary('/'), [TypeI32, TypeI32], TypeI32, t.params, cases); + }); + +g.test('remainder') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x % y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'remainder_const' : 'remainder_non_const' + ); + await run(t, binary('%'), [TypeI32, TypeI32], TypeI32, t.params, cases); + }); diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts new file mode 100644 index 0000000000..bf7789a635 --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts @@ -0,0 +1,213 @@ +export const description = ` +Execution Tests for the u32 arithmetic binary expression operations +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../gpu_test.js'; +import { TypeU32, TypeVec } from '../../../../util/conversion.js'; +import { fullU32Range, sparseU32Range, vectorU32Range } from '../../../../util/math.js'; +import { makeCaseCache } from '../case_cache.js'; +import { + allInputSources, + generateBinaryToU32Cases, + generateU32VectorBinaryToVectorCases, + generateVectorU32BinaryToVectorCases, + run, +} from '../expression.js'; + +import { binary } from './binary.js'; + +export const g = makeTestGroup(GPUTest); + +export const d = makeCaseCache('binary/u32_arithmetic', { + addition: () => { + return generateBinaryToU32Cases(fullU32Range(), fullU32Range(), (x, y) => { + return x + y; + }); + }, + subtraction: () => { + return generateBinaryToU32Cases(fullU32Range(), fullU32Range(), (x, y) => { + return x - y; + }); + }, + multiplication: () => { + return generateBinaryToU32Cases(fullU32Range(), fullU32Range(), (x, y) => { + return Math.imul(x, y); + }); + }, + division_non_const: () => { + return generateBinaryToU32Cases(fullU32Range(), fullU32Range(), (x, y) => { + if (y === 0) { + return x; + } + return x / y; + }); + }, + division_const: () => { + return generateBinaryToU32Cases(fullU32Range(), fullU32Range(), (x, y) => { + if (y === 0) { + return undefined; + } + return x / y; + }); + }, + remainder_non_const: () => { + return generateBinaryToU32Cases(fullU32Range(), fullU32Range(), (x, y) => { + if (y === 0) { + return 0; + } + return x % y; + }); + }, + remainder_const: () => { + return generateBinaryToU32Cases(fullU32Range(), fullU32Range(), (x, y) => { + if (y === 0) { + return undefined; + } + return x % y; + }); + }, + multiplication_scalar_vector2: () => { + return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(2), (x, y) => { + return Math.imul(x, y); + }); + }, + multiplication_scalar_vector3: () => { + return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(3), (x, y) => { + return Math.imul(x, y); + }); + }, + multiplication_scalar_vector4: () => { + return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(4), (x, y) => { + return Math.imul(x, y); + }); + }, + multiplication_vector2_scalar: () => { + return generateVectorU32BinaryToVectorCases(vectorU32Range(2), sparseU32Range(), (x, y) => { + return Math.imul(x, y); + }); + }, + multiplication_vector3_scalar: () => { + return generateVectorU32BinaryToVectorCases(vectorU32Range(3), sparseU32Range(), (x, y) => { + return Math.imul(x, y); + }); + }, + multiplication_vector4_scalar: () => { + return generateVectorU32BinaryToVectorCases(vectorU32Range(4), sparseU32Range(), (x, y) => { + return Math.imul(x, y); + }); + }, +}); + +g.test('addition') + .specURL('https://www.w3.org/TR/WGSL/#arithmetic-expr') + .desc( + ` +Expression: x + y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get('addition'); + await run(t, binary('+'), [TypeU32, TypeU32], TypeU32, t.params, cases); + }); + +g.test('subtraction') + .specURL('https://www.w3.org/TR/WGSL/#arithmetic-expr') + .desc( + ` +Expression: x - y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get('subtraction'); + await run(t, binary('-'), [TypeU32, TypeU32], TypeU32, t.params, cases); + }); + +g.test('multiplication') + .specURL('https://www.w3.org/TR/WGSL/#arithmetic-expr') + .desc( + ` +Expression: x * y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get('multiplication'); + await run(t, binary('*'), [TypeU32, TypeU32], TypeU32, t.params, cases); + }); + +g.test('division') + .specURL('https://www.w3.org/TR/WGSL/#arithmetic-expr') + .desc( + ` +Expression: x / y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'division_const' : 'division_non_const' + ); + await run(t, binary('/'), [TypeU32, TypeU32], TypeU32, t.params, cases); + }); + +g.test('remainder') + .specURL('https://www.w3.org/TR/WGSL/#arithmetic-expr') + .desc( + ` +Expression: x % y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) + ) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'remainder_const' : 'remainder_non_const' + ); + await run(t, binary('%'), [TypeU32, TypeU32], TypeU32, t.params, cases); + }); + +g.test('multiplication_scalar_vector') + .specURL('https://www.w3.org/TR/WGSL/#arithmetic-expr') + .desc( + ` +Expression: x * y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize_rhs', [2, 3, 4] as const) + ) + .fn(async t => { + const vec_size = t.params.vectorize_rhs; + const vec_type = TypeVec(vec_size, TypeU32); + const cases = await d.get(`multiplication_scalar_vector${vec_size}`); + await run(t, binary('*'), [TypeU32, vec_type], vec_type, t.params, cases); + }); + +g.test('multiplication_vector_scalar') + .specURL('https://www.w3.org/TR/WGSL/#arithmetic-expr') + .desc( + ` +Expression: x * y +` + ) + .params(u => + u.combine('inputSource', allInputSources).combine('vectorize_lhs', [2, 3, 4] as const) + ) + .fn(async t => { + const vec_size = t.params.vectorize_lhs; + const vec_type = TypeVec(vec_size, TypeU32); + const cases = await d.get(`multiplication_vector${vec_size}_scalar`); + await run(t, binary('*'), [vec_type, TypeU32], vec_type, t.params, cases); + }); |