export const description = ` Execution Tests for the bitwise binary expression operations `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { assert } from '../../../../../common/util/util.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../../gpu_test.js'; import { abstractIntBits, i32Bits, ScalarValue, scalarType, u32Bits, } from '../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../expression.js'; import { abstractIntBinary, binary, compoundBinary } from './binary.js'; export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest); /** * Collection of functions and values required to implement bitwise tests for a * specific scalar type */ interface ScalarImpl { // builder is a mostly a wrapper around type builders like 'i32Bits' that // handles the (number|bigint) type check. builder: (bits: bigint | number) => ScalarValue; size: 32 | 64; } const kScalarImpls = { i32: { builder: (bits: bigint | number): ScalarValue => { assert(typeof bits === 'number'); return i32Bits(bits); }, size: 32, } as ScalarImpl, u32: { builder: (bits: bigint | number): ScalarValue => { assert(typeof bits === 'number'); return u32Bits(bits); }, size: 32, } as ScalarImpl, 'abstract-int': { builder: (bits: bigint | number): ScalarValue => { assert(typeof bits === 'bigint'); return abstractIntBits(bits); }, size: 64, } as ScalarImpl, }; /** Wrapper for converting from input type strings to the appropriate implementation */ function scalarImplForInputType(inputType: string): ScalarImpl { assert(inputType === 'i32' || inputType === 'u32' || inputType === 'abstract-int'); return kScalarImpls[inputType]; } /** Manually calculated bitwise-or cases used a check that the CTS test is correct */ const kBitwiseOrStaticPatterns = { 32: [ { input: [0b00000000000000000000000000000000, 0b00000000000000000000000000000000], expected: 0b00000000000000000000000000000000, }, { input: [0b11111111111111111111111111111111, 0b00000000000000000000000000000000], expected: 0b11111111111111111111111111111111, }, { input: [0b00000000000000000000000000000000, 0b11111111111111111111111111111111], expected: 0b11111111111111111111111111111111, }, { input: [0b11111111111111111111111111111111, 0b11111111111111111111111111111111], expected: 0b11111111111111111111111111111111, }, { input: [0b10100100010010100100010010100100, 0b00000000000000000000000000000000], expected: 0b10100100010010100100010010100100, }, { input: [0b00000000000000000000000000000000, 0b10100100010010100100010010100100], expected: 0b10100100010010100100010010100100, }, { input: [0b01010010001001010010001001010010, 0b10100100010010100100010010100100], expected: 0b11110110011011110110011011110110, }, ], 64: [ { input: [ 0b0000000000000000000000000000000000000000000000000000000000000000n, 0b0000000000000000000000000000000000000000000000000000000000000000n, ], expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, }, { input: [ 0b1111111111111111111111111111111111111111111111111111111111111111n, 0b0000000000000000000000000000000000000000000000000000000000000000n, ], expected: 0b1111111111111111111111111111111111111111111111111111111111111111n, }, { input: [ 0b0000000000000000000000000000000000000000000000000000000000000000n, 0b1111111111111111111111111111111111111111111111111111111111111111n, ], expected: 0b1111111111111111111111111111111111111111111111111111111111111111n, }, { input: [ 0b1111111111111111111111111111111111111111111111111111111111111111n, 0b1111111111111111111111111111111111111111111111111111111111111111n, ], expected: 0b1111111111111111111111111111111111111111111111111111111111111111n, }, { input: [ 0b1010010001001010010001001010010010100100010010100100010010100100n, 0b0000000000000000000000000000000000000000000000000000000000000000n, ], expected: 0b1010010001001010010001001010010010100100010010100100010010100100n, }, { input: [ 0b0000000000000000000000000000000000000000000000000000000000000000n, 0b1010010001001010010001001010010010100100010010100100010010100100n, ], expected: 0b1010010001001010010001001010010010100100010010100100010010100100n, }, { input: [ 0b0101001000100101001000100101001010100100010010100100010010100100n, 0b1010010001001010010001001010010010100100010010100100010010100100n, ], expected: 0b1111011001101111011001101111011010100100010010100100010010100100n, }, ], }; /** @returns a set of bitwise-or cases for the specific input type */ function makeBitwiseOrCases(inputType: string) { const impl = scalarImplForInputType(inputType); const indices = impl.size === 64 ? [...Array(impl.size).keys()].map(BigInt) : [...Array(impl.size).keys()]; return [ ...kBitwiseOrStaticPatterns[impl.size].map(c => { return { input: c.input.map(impl.builder), expected: impl.builder(c.expected), }; }), // Permute all combinations of a single bit being set for the LHS and RHS ...indices.flatMap(i => { const lhs = typeof i === 'bigint' ? 1n << i : 1 << i; return indices.map(j => { const rhs = typeof j === 'bigint' ? 1n << j : 1 << j; assert(typeof lhs === typeof rhs); const result = typeof lhs === 'bigint' ? lhs | (rhs as bigint) : lhs | (rhs as number); return { input: [impl.builder(lhs), impl.builder(rhs)], expected: impl.builder(result) }; }); }), ]; } g.test('bitwise_or') .specURL('https://www.w3.org/TR/WGSL/#bit-expr') .desc( ` e1 | e2: T T is i32, u32, abstractInt, vecN, vecN, or vecN Bitwise-or. Component-wise when T is a vector. ` ) .params(u => u .combine('type', ['i32', 'u32', 'abstract-int'] as const) .combine('inputSource', allInputSources) .combine('vectorize', [undefined, 2, 3, 4] as const) ) .fn(async t => { t.skipIf( t.params.type === 'abstract-int' && !onlyConstInputSource.includes(t.params.inputSource) ); const type = scalarType(t.params.type); const cases = makeBitwiseOrCases(t.params.type); const builder = t.params.type === 'abstract-int' ? abstractIntBinary('|') : binary('|'); await run(t, builder, [type, type], type, t.params, cases); }); g.test('bitwise_or_compound') .specURL('https://www.w3.org/TR/WGSL/#bit-expr') .desc( ` e1 |= e2: T T is i32, u32, vecN, or vecN 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 cases = makeBitwiseOrCases(t.params.type); await run(t, compoundBinary('|='), [type, type], type, t.params, cases); }); /** Manually calculated bitwise-and cases used a check that the CTS test is correct */ const kBitwiseAndStaticPatterns = { 32: [ { input: [0b00000000000000000000000000000000, 0b00000000000000000000000000000000], expected: 0b00000000000000000000000000000000, }, { input: [0b11111111111111111111111111111111, 0b00000000000000000000000000000000], expected: 0b00000000000000000000000000000000, }, { input: [0b00000000000000000000000000000000, 0b11111111111111111111111111111111], expected: 0b00000000000000000000000000000000, }, { input: [0b11111111111111111111111111111111, 0b11111111111111111111111111111111], expected: 0b11111111111111111111111111111111, }, { input: [0b10100100010010100100010010100100, 0b00000000000000000000000000000000], expected: 0b00000000000000000000000000000000, }, { input: [0b10100100010010100100010010100100, 0b11111111111111111111111111111111], expected: 0b10100100010010100100010010100100, }, { input: [0b00000000000000000000000000000000, 0b10100100010010100100010010100100], expected: 0b00000000000000000000000000000000, }, { input: [0b11111111111111111111111111111111, 0b10100100010010100100010010100100], expected: 0b10100100010010100100010010100100, }, { input: [0b01010010001001010010001001010010, 0b01011011101101011011101101011011], expected: 0b01010010001001010010001001010010, }, ], 64: [ { input: [ 0b0000000000000000000000000000000000000000000000000000000000000000n, 0b0000000000000000000000000000000000000000000000000000000000000000n, ], expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, }, { input: [ 0b1111111111111111111111111111111111111111111111111111111111111111n, 0b0000000000000000000000000000000000000000000000000000000000000000n, ], expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, }, { input: [ 0b0000000000000000000000000000000000000000000000000000000000000000n, 0b1111111111111111111111111111111111111111111111111111111111111111n, ], expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, }, { input: [ 0b1111111111111111111111111111111111111111111111111111111111111111n, 0b1111111111111111111111111111111111111111111111111111111111111111n, ], expected: 0b1111111111111111111111111111111111111111111111111111111111111111n, }, { input: [ 0b1010010001001010010001001010010010100100010010100100010010100100n, 0b0000000000000000000000000000000000000000000000000000000000000000n, ], expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, }, { input: [ 0b1010010001001010010001001010010010100100010010100100010010100100n, 0b1111111111111111111111111111111111111111111111111111111111111111n, ], expected: 0b1010010001001010010001001010010010100100010010100100010010100100n, }, { input: [ 0b0000000000000000000000000000000000000000000000000000000000000000n, 0b1010010001001010010001001010010010100100010010100100010010100100n, ], expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, }, { input: [ 0b1111111111111111111111111111111111111111111111111111111111111111n, 0b1010010001001010010001001010010010100100010010100100010010100100n, ], expected: 0b1010010001001010010001001010010010100100010010100100010010100100n, }, { input: [ 0b0101001000100101001000100101001001010010001001010010001001010010n, 0b0101101110110101101110110101101101011011101101011011101101011011n, ], expected: 0b0101001000100101001000100101001001010010001001010010001001010010n, }, ], }; /** @returns a set of bitwise-or cases for the specific input type */ function makeBitwiseAndCases(inputType: string) { const impl = scalarImplForInputType(inputType); const indices = impl.size === 64 ? [...Array(impl.size).keys()].map(BigInt) : [...Array(impl.size).keys()]; return [ ...kBitwiseAndStaticPatterns[impl.size].map(c => { return { input: c.input.map(impl.builder), expected: impl.builder(c.expected), }; }), // Permute all combinations of a single bit being set for the LHS and all but one bit set for the RHS ...indices.flatMap(i => { const lhs = typeof i === 'bigint' ? 1n << i : 1 << i; return indices.map(j => { const rhs = typeof j === 'bigint' ? 0xffffffffffffffffn ^ (1n << j) : 0xffffffff ^ (1 << j); assert(typeof lhs === typeof rhs); const result = typeof lhs === 'bigint' ? lhs & (rhs as bigint) : lhs & (rhs as number); return { input: [impl.builder(lhs), impl.builder(rhs)], expected: impl.builder(result) }; }); }), ]; } g.test('bitwise_and') .specURL('https://www.w3.org/TR/WGSL/#bit-expr') .desc( ` e1 & e2: T T is i32, u32, AbstractInt, vecN, vecN, or vecN Bitwise-and. Component-wise when T is a vector. ` ) .params(u => u .combine('type', ['i32', 'u32', 'abstract-int'] as const) .combine('inputSource', allInputSources) .combine('vectorize', [undefined, 2, 3, 4] as const) ) .fn(async t => { t.skipIf( t.params.type === 'abstract-int' && !onlyConstInputSource.includes(t.params.inputSource) ); const type = scalarType(t.params.type); const cases = makeBitwiseAndCases(t.params.type); const builder = t.params.type === 'abstract-int' ? abstractIntBinary('&') : binary('&'); await run(t, builder, [type, type], type, t.params, cases); }); g.test('bitwise_and_compound') .specURL('https://www.w3.org/TR/WGSL/#bit-expr') .desc( ` e1 &= e2: T T is i32, u32, vecN, or vecN 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 cases = makeBitwiseAndCases(t.params.type); await run(t, compoundBinary('&='), [type, type], type, t.params, cases); }); /** Manually calculated bitwise-or cases used a check that the CTS test is correct */ const kBitwiseExclusiveOrStaticPatterns = { 32: [ { input: [0b00000000000000000000000000000000, 0b00000000000000000000000000000000], expected: 0b00000000000000000000000000000000, }, { input: [0b11111111111111111111111111111111, 0b00000000000000000000000000000000], expected: 0b11111111111111111111111111111111, }, { input: [0b00000000000000000000000000000000, 0b11111111111111111111111111111111], expected: 0b11111111111111111111111111111111, }, { input: [0b11111111111111111111111111111111, 0b11111111111111111111111111111111], expected: 0b00000000000000000000000000000000, }, { input: [0b10100100010010100100010010100100, 0b00000000000000000000000000000000], expected: 0b10100100010010100100010010100100, }, { input: [0b10100100010010100100010010100100, 0b11111111111111111111111111111111], expected: 0b01011011101101011011101101011011, }, { input: [0b00000000000000000000000000000000, 0b10100100010010100100010010100100], expected: 0b10100100010010100100010010100100, }, { input: [0b11111111111111111111111111111111, 0b10100100010010100100010010100100], expected: 0b01011011101101011011101101011011, }, { input: [0b01010010001001010010001001010010, 0b01011011101101011011101101011011], expected: 0b00001001100100001001100100001001, }, ], 64: [ { input: [ 0b0000000000000000000000000000000000000000000000000000000000000000n, 0b0000000000000000000000000000000000000000000000000000000000000000n, ], expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, }, { input: [ 0b1111111111111111111111111111111111111111111111111111111111111111n, 0b0000000000000000000000000000000000000000000000000000000000000000n, ], expected: 0b1111111111111111111111111111111111111111111111111111111111111111n, }, { input: [ 0b0000000000000000000000000000000000000000000000000000000000000000n, 0b1111111111111111111111111111111111111111111111111111111111111111n, ], expected: 0b1111111111111111111111111111111111111111111111111111111111111111n, }, { input: [ 0b1111111111111111111111111111111111111111111111111111111111111111n, 0b1111111111111111111111111111111111111111111111111111111111111111n, ], expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, }, { input: [ 0b1010010001001010010001001010010010100100010010100100010010100100n, 0b0000000000000000000000000000000000000000000000000000000000000000n, ], expected: 0b1010010001001010010001001010010010100100010010100100010010100100n, }, { input: [ 0b1010010001001010010001001010010010100100010010100100010010100100n, 0b1111111111111111111111111111111111111111111111111111111111111111n, ], expected: 0b0101101110110101101110110101101101011011101101011011101101011011n, }, { input: [ 0b0000000000000000000000000000000000000000000000000000000000000000n, 0b1010010001001010010001001010010010100100010010100100010010100100n, ], expected: 0b1010010001001010010001001010010010100100010010100100010010100100n, }, { input: [ 0b1111111111111111111111111111111111111111111111111111111111111111n, 0b1010010001001010010001001010010010100100010010100100010010100100n, ], expected: 0b0101101110110101101110110101101101011011101101011011101101011011n, }, { input: [ 0b0101001000100101001000100101001001010010001001010010001001010010n, 0b0101101110110101101110110101101101011011101101011011101101011011n, ], expected: 0b0000100110010000100110010000100100001001100100001001100100001001n, }, ], }; /** @returns a set of bitwise-xor cases for the specific input type */ function makeBitwiseExclusiveOrCases(inputType: string) { const impl = scalarImplForInputType(inputType); const indices = impl.size === 64 ? [...Array(impl.size).keys()].map(BigInt) : [...Array(impl.size).keys()]; return [ ...kBitwiseExclusiveOrStaticPatterns[impl.size].map(c => { return { input: c.input.map(impl.builder), expected: impl.builder(c.expected), }; }), // Permute all combinations of a single bit being set for the LHS and all but one bit set for the RHS ...indices.flatMap(i => { const lhs = typeof i === 'bigint' ? 1n << i : 1 << i; return indices.map(j => { const rhs = typeof j === 'bigint' ? 0xffffffffffffffffn ^ (1n << j) : 0xffffffff ^ (1 << j); assert(typeof lhs === typeof rhs); const result = typeof lhs === 'bigint' ? lhs ^ (rhs as bigint) : lhs ^ (rhs as number); return { input: [impl.builder(lhs), impl.builder(rhs)], expected: impl.builder(result) }; }); }), ]; } g.test('bitwise_exclusive_or') .specURL('https://www.w3.org/TR/WGSL/#bit-expr') .desc( ` e1 ^ e2: T T is i32, u32, abstractInt, vecN, vecN, or vecN Bitwise-exclusive-or. Component-wise when T is a vector. ` ) .params(u => u .combine('type', ['i32', 'u32', 'abstract-int'] as const) .combine('inputSource', allInputSources) .combine('vectorize', [undefined, 2, 3, 4] as const) ) .fn(async t => { t.skipIf( t.params.type === 'abstract-int' && !onlyConstInputSource.includes(t.params.inputSource) ); const type = scalarType(t.params.type); const cases = makeBitwiseExclusiveOrCases(t.params.type); const builder = t.params.type === 'abstract-int' ? abstractIntBinary('^') : binary('^'); await run(t, builder, [type, type], type, t.params, cases); }); g.test('bitwise_exclusive_or_compound') .specURL('https://www.w3.org/TR/WGSL/#bit-expr') .desc( ` e1 ^= e2: T T is i32, u32, vecN, or vecN 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 cases = makeBitwiseExclusiveOrCases(t.params.type); await run(t, compoundBinary('^='), [type, type], type, t.params, cases); });