blob: f287f5a987c40f3ea669f33037a546d33770d33b [file] [log] [blame]
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<i32>, vecN<u32>, or vecN<abstractInt>
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<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 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<i32>, vecN<u32>, or vecN<AbstractInt>
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<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 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<i32>, vecN<u32>, or vecN<abstractInt>
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<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 cases = makeBitwiseExclusiveOrCases(t.params.type);
await run(t, compoundBinary('^='), [type, type], type, t.params, cases);
});