summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary')
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/address_of_and_indirection.spec.ts171
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_arithmetic.cache.ts13
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts30
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_assignment.cache.ts51
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts66
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_arithmetic.cache.ts11
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_arithmetic.spec.ts30
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_assignment.cache.ts21
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_assignment.spec.ts65
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_complement.spec.ts32
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts54
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts87
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_logical.spec.ts4
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_arithmetic.cache.ts13
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts18
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_conversion.cache.ts135
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts226
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_arithmetic.cache.ts13
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts18
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_conversion.cache.ts79
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts113
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_arithmetic.cache.ts11
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts15
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts17
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_conversion.cache.ts116
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts158
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts17
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_conversion.cache.ts107
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts144
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/unary.ts8
30 files changed, 1209 insertions, 634 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/address_of_and_indirection.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/address_of_and_indirection.spec.ts
new file mode 100644
index 0000000000..c4961558e0
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/address_of_and_indirection.spec.ts
@@ -0,0 +1,171 @@
+export const description = `
+Execution Tests for unary address-of and indirection (dereference)
+`;
+
+import { makeTestGroup } from '../../../../../common/framework/test_group.js';
+import { keysOf } from '../../../../../common/util/data_tables.js';
+import { GPUTest } from '../../../../gpu_test.js';
+import { ScalarKind, scalarType } from '../../../../util/conversion.js';
+import { sparseScalarF32Range } from '../../../../util/math.js';
+import {
+ allButConstInputSource,
+ basicExpressionWithPredeclarationBuilder,
+ run,
+} from '../expression.js';
+
+export const g = makeTestGroup(GPUTest);
+
+// All the ways to deref an expression
+const kDerefCases = {
+ deref_address_of_identifier: {
+ wgsl: '(*(&a))',
+ requires_pointer_composite_access: false,
+ },
+ deref_pointer: {
+ wgsl: '(*p)',
+ requires_pointer_composite_access: false,
+ },
+ address_of_identifier: {
+ wgsl: '(&a)',
+ requires_pointer_composite_access: true,
+ },
+ pointer: {
+ wgsl: 'p',
+ requires_pointer_composite_access: true,
+ },
+};
+
+g.test('deref')
+ .specURL('https://www.w3.org/TR/WGSL/#indirection')
+ .desc(
+ `
+Expression: *e
+
+Pointer expression dereference.
+`
+ )
+ .params(u =>
+ u
+ .combine('inputSource', allButConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ .combine('scalarType', ['bool', 'u32', 'i32', 'f32', 'f16'] as ScalarKind[])
+ .combine('derefType', keysOf(kDerefCases))
+ .filter(p => !kDerefCases[p.derefType].requires_pointer_composite_access)
+ )
+ .beforeAllSubcases(t => {
+ if (t.params.scalarType === 'f16') {
+ t.selectDeviceOrSkipTestCase({ requiredFeatures: ['shader-f16'] });
+ }
+ })
+ .fn(async t => {
+ const ty = scalarType(t.params.scalarType);
+ const cases = sparseScalarF32Range().map(e => {
+ return { input: ty.create(e), expected: ty.create(e) };
+ });
+ const elemType = ty.kind;
+ const type = t.params.vectorize ? `vec${t.params.vectorize}<${elemType}>` : elemType;
+ const shaderBuilder = basicExpressionWithPredeclarationBuilder(
+ value => `get_dereferenced_value(${value})`,
+ `fn get_dereferenced_value(value: ${type}) -> ${type} {
+ var a = value;
+ let p = &a;
+ return ${kDerefCases[t.params.derefType].wgsl};
+ }`
+ );
+ await run(t, shaderBuilder, [ty], ty, t.params, cases);
+ });
+
+g.test('deref_index')
+ .specURL('https://www.w3.org/TR/WGSL/#logical-expr')
+ .desc(
+ `
+Expression: (*e)[index]
+
+Pointer expression dereference as lhs of index accessor expression
+`
+ )
+ .params(u =>
+ u
+ .combine('inputSource', allButConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ .combine('scalarType', ['bool', 'u32', 'i32', 'f32', 'f16'] as ScalarKind[])
+ .combine('derefType', keysOf(kDerefCases))
+ )
+ .beforeAllSubcases(t => {
+ if (t.params.scalarType === 'f16') {
+ t.selectDeviceOrSkipTestCase({ requiredFeatures: ['shader-f16'] });
+ }
+ })
+ .fn(async t => {
+ if (
+ kDerefCases[t.params.derefType].requires_pointer_composite_access &&
+ !t.hasLanguageFeature('pointer_composite_access')
+ ) {
+ return;
+ }
+
+ const ty = scalarType(t.params.scalarType);
+ const cases = sparseScalarF32Range().map(e => {
+ return { input: ty.create(e), expected: ty.create(e) };
+ });
+ const elemType = ty.kind;
+ const type = t.params.vectorize ? `vec${t.params.vectorize}<${elemType}>` : elemType;
+ const shaderBuilder = basicExpressionWithPredeclarationBuilder(
+ value => `get_dereferenced_value(${value})`,
+ `fn get_dereferenced_value(value: ${type}) -> ${type} {
+ var a = array<${type}, 1>(value);
+ let p = &a;
+ return ${kDerefCases[t.params.derefType].wgsl}[0];
+ }`
+ );
+ await run(t, shaderBuilder, [ty], ty, t.params, cases);
+ });
+
+g.test('deref_member')
+ .specURL('https://www.w3.org/TR/WGSL/#logical-expr')
+ .desc(
+ `
+Expression: (*e).member
+
+Pointer expression dereference as lhs of member accessor expression
+`
+ )
+ .params(u =>
+ u
+ .combine('inputSource', allButConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ .combine('scalarType', ['bool', 'u32', 'i32', 'f32', 'f16'] as ScalarKind[])
+ .combine('derefType', keysOf(kDerefCases))
+ )
+ .beforeAllSubcases(t => {
+ if (t.params.scalarType === 'f16') {
+ t.selectDeviceOrSkipTestCase({ requiredFeatures: ['shader-f16'] });
+ }
+ })
+ .fn(async t => {
+ if (
+ kDerefCases[t.params.derefType].requires_pointer_composite_access &&
+ !t.hasLanguageFeature('pointer_composite_access')
+ ) {
+ return;
+ }
+
+ const ty = scalarType(t.params.scalarType);
+ const cases = sparseScalarF32Range().map(e => {
+ return { input: ty.create(e), expected: ty.create(e) };
+ });
+ const elemType = ty.kind;
+ const type = t.params.vectorize ? `vec${t.params.vectorize}<${elemType}>` : elemType;
+ const shaderBuilder = basicExpressionWithPredeclarationBuilder(
+ value => `get_dereferenced_value(${value})`,
+ `struct S {
+ m : ${type}
+ }
+ fn get_dereferenced_value(value: ${type}) -> ${type} {
+ var a = S(value);
+ let p = &a;
+ return ${kDerefCases[t.params.derefType].wgsl}.m;
+ }`
+ );
+ await run(t, shaderBuilder, [ty], ty, t.params, cases);
+ });
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_arithmetic.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_arithmetic.cache.ts
new file mode 100644
index 0000000000..4f274e8922
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_arithmetic.cache.ts
@@ -0,0 +1,13 @@
+import { FP } from '../../../../util/floating_point.js';
+import { scalarF64Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/af_arithmetic', {
+ negation: () => {
+ return FP.abstract.generateScalarToIntervalCases(
+ scalarF64Range({ neg_norm: 250, neg_sub: 20, pos_sub: 20, pos_norm: 250 }),
+ 'unfiltered',
+ FP.abstract.negationInterval
+ );
+ },
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts
index 182c0d76a9..686d4b7c4a 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts
@@ -1,29 +1,17 @@
export const description = `
-Execution Tests for AbstractFloat arithmetic unary expression operations
+Execution Tests for Type.abstractFloat arithmetic unary expression operations
`;
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { TypeAbstractFloat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { fullF64Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
+import { Type } from '../../../../util/conversion.js';
import { onlyConstInputSource, run } from '../expression.js';
-import { abstractUnary } from './unary.js';
+import { d } from './af_arithmetic.cache.js';
+import { abstractFloatUnary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unary/af_arithmetic', {
- negation: () => {
- return FP.abstract.generateScalarToIntervalCases(
- fullF64Range({ neg_norm: 250, neg_sub: 20, pos_sub: 20, pos_norm: 250 }),
- 'unfiltered',
- FP.abstract.negationInterval
- );
- },
-});
-
g.test('negation')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
@@ -39,5 +27,13 @@ Accuracy: Correctly rounded
)
.fn(async t => {
const cases = await d.get('negation');
- await run(t, abstractUnary('-'), [TypeAbstractFloat], TypeAbstractFloat, t.params, cases, 1);
+ await run(
+ t,
+ abstractFloatUnary('-'),
+ [Type.abstractFloat],
+ Type.abstractFloat,
+ t.params,
+ cases,
+ 1
+ );
});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_assignment.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_assignment.cache.ts
new file mode 100644
index 0000000000..7c607927fe
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_assignment.cache.ts
@@ -0,0 +1,51 @@
+import { kValue } from '../../../../util/constants.js';
+import { abstractFloat } from '../../../../util/conversion.js';
+import { FP } from '../../../../util/floating_point.js';
+import {
+ isSubnormalNumberF64,
+ limitedScalarF64Range,
+ scalarF64Range,
+} from '../../../../util/math.js';
+import { reinterpretU64AsF64 } from '../../../../util/reinterpret.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/af_assignment', {
+ abstract: () => {
+ const inputs = [
+ // Values that are useful for debugging the underlying framework/shader code, since it cannot be directly unit tested.
+ 0,
+ 0.5,
+ 0.5,
+ 1,
+ -1,
+ reinterpretU64AsF64(0x7000_0000_0000_0001n), // smallest magnitude negative subnormal with non-zero mantissa
+ reinterpretU64AsF64(0x0000_0000_0000_0001n), // smallest magnitude positive subnormal with non-zero mantissa
+ reinterpretU64AsF64(0x600a_aaaa_5555_5555n), // negative subnormal with obvious pattern
+ reinterpretU64AsF64(0x000a_aaaa_5555_5555n), // positive subnormal with obvious pattern
+ reinterpretU64AsF64(0x0010_0000_0000_0001n), // smallest magnitude negative normal with non-zero mantissa
+ reinterpretU64AsF64(0x0010_0000_0000_0001n), // smallest magnitude positive normal with non-zero mantissa
+ reinterpretU64AsF64(0xf555_5555_aaaa_aaaan), // negative normal with obvious pattern
+ reinterpretU64AsF64(0x5555_5555_aaaa_aaaan), // positive normal with obvious pattern
+ reinterpretU64AsF64(0xffef_ffff_ffff_ffffn), // largest magnitude negative normal
+ reinterpretU64AsF64(0x7fef_ffff_ffff_ffffn), // largest magnitude positive normal
+ // WebGPU implementation stressing values
+ ...scalarF64Range(),
+ ];
+ return inputs.map(f => {
+ return {
+ input: abstractFloat(f),
+ expected: isSubnormalNumberF64(f) ? abstractFloat(0) : abstractFloat(f),
+ };
+ });
+ },
+ f32: () => {
+ return limitedScalarF64Range(kValue.f32.negative.min, kValue.f32.positive.max).map(f => {
+ return { input: abstractFloat(f), expected: FP.f32.correctlyRoundedInterval(f) };
+ });
+ },
+ f16: () => {
+ return limitedScalarF64Range(kValue.f16.negative.min, kValue.f16.positive.max).map(f => {
+ return { input: abstractFloat(f), expected: FP.f16.correctlyRoundedInterval(f) };
+ });
+ },
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts
index 141d87d0f2..001c47e117 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts
@@ -4,20 +4,17 @@ Execution Tests for assignment of AbstractFloats
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { kValue } from '../../../../util/constants.js';
-import { abstractFloat, TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { filteredF64Range, fullF64Range, isSubnormalNumberF64 } from '../../../../util/math.js';
-import { reinterpretU64AsF64 } from '../../../../util/reinterpret.js';
-import { makeCaseCache } from '../case_cache.js';
+import { Type } from '../../../../util/conversion.js';
import {
+ ShaderBuilder,
abstractFloatShaderBuilder,
basicExpressionBuilder,
onlyConstInputSource,
run,
- ShaderBuilder,
} from '../expression.js';
+import { d } from './af_assignment.cache.js';
+
function concrete_assignment(): ShaderBuilder {
return basicExpressionBuilder(value => `${value}`);
}
@@ -28,47 +25,6 @@ function abstract_assignment(): ShaderBuilder {
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unary/af_assignment', {
- abstract: () => {
- const inputs = [
- // Values that are useful for debugging the underlying framework/shader code, since it cannot be directly unit tested.
- 0,
- 0.5,
- 0.5,
- 1,
- -1,
- reinterpretU64AsF64(0x7000_0000_0000_0001n), // smallest magnitude negative subnormal with non-zero mantissa
- reinterpretU64AsF64(0x0000_0000_0000_0001n), // smallest magnitude positive subnormal with non-zero mantissa
- reinterpretU64AsF64(0x600a_aaaa_5555_5555n), // negative subnormal with obvious pattern
- reinterpretU64AsF64(0x000a_aaaa_5555_5555n), // positive subnormal with obvious pattern
- reinterpretU64AsF64(0x0010_0000_0000_0001n), // smallest magnitude negative normal with non-zero mantissa
- reinterpretU64AsF64(0x0010_0000_0000_0001n), // smallest magnitude positive normal with non-zero mantissa
- reinterpretU64AsF64(0xf555_5555_aaaa_aaaan), // negative normal with obvious pattern
- reinterpretU64AsF64(0x5555_5555_aaaa_aaaan), // positive normal with obvious pattern
- reinterpretU64AsF64(0xffef_ffff_ffff_ffffn), // largest magnitude negative normal
- reinterpretU64AsF64(0x7fef_ffff_ffff_ffffn), // largest magnitude positive normal
- // WebGPU implementation stressing values
- ...fullF64Range(),
- ];
- return inputs.map(f => {
- return {
- input: abstractFloat(f),
- expected: isSubnormalNumberF64(f) ? abstractFloat(0) : abstractFloat(f),
- };
- });
- },
- f32: () => {
- return filteredF64Range(kValue.f32.negative.min, kValue.f32.positive.max).map(f => {
- return { input: abstractFloat(f), expected: FP.f32.correctlyRoundedInterval(f) };
- });
- },
- f16: () => {
- return filteredF64Range(kValue.f16.negative.min, kValue.f16.positive.max).map(f => {
- return { input: abstractFloat(f), expected: FP.f16.correctlyRoundedInterval(f) };
- });
- },
-});
-
g.test('abstract')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-conversion')
.desc(
@@ -79,7 +35,15 @@ testing that extracting abstract floats works
.params(u => u.combine('inputSource', onlyConstInputSource))
.fn(async t => {
const cases = await d.get('abstract');
- await run(t, abstract_assignment(), [TypeAbstractFloat], TypeAbstractFloat, t.params, cases, 1);
+ await run(
+ t,
+ abstract_assignment(),
+ [Type.abstractFloat],
+ Type.abstractFloat,
+ t.params,
+ cases,
+ 1
+ );
});
g.test('f32')
@@ -92,7 +56,7 @@ concretizing to f32
.params(u => u.combine('inputSource', onlyConstInputSource))
.fn(async t => {
const cases = await d.get('f32');
- await run(t, concrete_assignment(), [TypeAbstractFloat], TypeF32, t.params, cases);
+ await run(t, concrete_assignment(), [Type.abstractFloat], Type.f32, t.params, cases);
});
g.test('f16')
@@ -108,5 +72,5 @@ concretizing to f16
.params(u => u.combine('inputSource', onlyConstInputSource))
.fn(async t => {
const cases = await d.get('f16');
- await run(t, concrete_assignment(), [TypeAbstractFloat], TypeF16, t.params, cases);
+ await run(t, concrete_assignment(), [Type.abstractFloat], Type.f16, t.params, cases);
});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_arithmetic.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_arithmetic.cache.ts
new file mode 100644
index 0000000000..904c0bc700
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_arithmetic.cache.ts
@@ -0,0 +1,11 @@
+import { abstractInt } from '../../../../util/conversion.js';
+import { fullI64Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/ai_arithmetic', {
+ negation: () => {
+ return fullI64Range().map(e => {
+ return { input: abstractInt(e), expected: abstractInt(-e) };
+ });
+ },
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_arithmetic.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_arithmetic.spec.ts
new file mode 100644
index 0000000000..625a38b2d5
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_arithmetic.spec.ts
@@ -0,0 +1,30 @@
+export const description = `
+Execution Tests for the abstract integer arithmetic unary expression operations
+`;
+
+import { makeTestGroup } from '../../../../../common/framework/test_group.js';
+import { GPUTest } from '../../../../gpu_test.js';
+import { Type } from '../../../../util/conversion.js';
+import { onlyConstInputSource, run } from '../expression.js';
+
+import { d } from './ai_arithmetic.cache.js';
+import { abstractIntUnary } from './unary.js';
+
+export const g = makeTestGroup(GPUTest);
+
+g.test('negation')
+ .specURL('https://www.w3.org/TR/WGSL/#arithmetic-expr')
+ .desc(
+ `
+Expression: -x
+`
+ )
+ .params(u =>
+ u
+ .combine('inputSource', onlyConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ )
+ .fn(async t => {
+ const cases = await d.get('negation');
+ await run(t, abstractIntUnary('-'), [Type.abstractInt], Type.abstractInt, t.params, cases);
+ });
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_assignment.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_assignment.cache.ts
new file mode 100644
index 0000000000..0fa4f2efc2
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_assignment.cache.ts
@@ -0,0 +1,21 @@
+import { abstractInt, i32, u32 } from '../../../../util/conversion.js';
+import { fullI32Range, fullI64Range, fullU32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/ai_assignment', {
+ abstract: () => {
+ return fullI64Range().map(n => {
+ return { input: abstractInt(n), expected: abstractInt(n) };
+ });
+ },
+ i32: () => {
+ return fullI32Range().map(n => {
+ return { input: abstractInt(BigInt(n)), expected: i32(n) };
+ });
+ },
+ u32: () => {
+ return fullU32Range().map(n => {
+ return { input: abstractInt(BigInt(n)), expected: u32(n) };
+ });
+ },
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_assignment.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_assignment.spec.ts
new file mode 100644
index 0000000000..fe1ba2d9fc
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_assignment.spec.ts
@@ -0,0 +1,65 @@
+export const description = `
+Execution Tests for assignment of AbstractInts
+`;
+
+import { makeTestGroup } from '../../../../../common/framework/test_group.js';
+import { GPUTest } from '../../../../gpu_test.js';
+import { Type } from '../../../../util/conversion.js';
+import {
+ ShaderBuilder,
+ abstractIntShaderBuilder,
+ basicExpressionBuilder,
+ onlyConstInputSource,
+ run,
+} from '../expression.js';
+
+import { d } from './ai_assignment.cache.js';
+
+function concrete_assignment(): ShaderBuilder {
+ return basicExpressionBuilder(value => `${value}`);
+}
+
+function abstract_assignment(): ShaderBuilder {
+ return abstractIntShaderBuilder(value => `${value}`);
+}
+
+export const g = makeTestGroup(GPUTest);
+
+g.test('abstract')
+ .specURL('https://www.w3.org/TR/WGSL/#abstract-types')
+ .desc(
+ `
+testing that extracting abstract ints works
+`
+ )
+ .params(u => u.combine('inputSource', onlyConstInputSource))
+ .fn(async t => {
+ const cases = await d.get('abstract');
+ await run(t, abstract_assignment(), [Type.abstractInt], Type.abstractInt, t.params, cases, 1);
+ });
+
+g.test('i32')
+ .specURL('https://www.w3.org/TR/WGSL/#i32-builtin')
+ .desc(
+ `
+concretizing to i32
+`
+ )
+ .params(u => u.combine('inputSource', onlyConstInputSource))
+ .fn(async t => {
+ const cases = await d.get('i32');
+ await run(t, concrete_assignment(), [Type.abstractInt], Type.i32, t.params, cases);
+ });
+
+g.test('u32')
+ .specURL('https://www.w3.org/TR/WGSL/#u32-builtin')
+ .desc(
+ `
+concretizing to u32
+`
+ )
+ .params(u => u.combine('inputSource', onlyConstInputSource))
+ .fn(async t => {
+ const cases = await d.get('u32');
+ await run(t, concrete_assignment(), [Type.abstractInt], Type.u32, t.params, cases);
+ });
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_complement.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_complement.spec.ts
new file mode 100644
index 0000000000..507ae219cb
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/ai_complement.spec.ts
@@ -0,0 +1,32 @@
+export const description = `
+Execution Tests for the Type.abstractInt bitwise complement operation
+`;
+
+import { makeTestGroup } from '../../../../../common/framework/test_group.js';
+import { GPUTest } from '../../../../gpu_test.js';
+import { abstractInt, Type } from '../../../../util/conversion.js';
+import { fullI64Range } from '../../../../util/math.js';
+import { onlyConstInputSource, run } from '../expression.js';
+
+import { abstractIntUnary } from './unary.js';
+
+export const g = makeTestGroup(GPUTest);
+
+g.test('complement')
+ .specURL('https://www.w3.org/TR/WGSL/#bit-expr')
+ .desc(
+ `
+Expression: ~x
+`
+ )
+ .params(u =>
+ u
+ .combine('inputSource', onlyConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ )
+ .fn(async t => {
+ const cases = fullI64Range().map(e => {
+ return { input: abstractInt(e), expected: abstractInt(~e) };
+ });
+ await run(t, abstractIntUnary('~'), [Type.abstractInt], Type.abstractInt, t.params, cases);
+ });
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts
new file mode 100644
index 0000000000..5b16c49c42
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts
@@ -0,0 +1,54 @@
+import { anyOf } from '../../../../util/compare.js';
+import { ScalarValue, bool, f16, f32, i32, u32 } from '../../../../util/conversion.js';
+import {
+ fullI32Range,
+ fullU32Range,
+ isSubnormalNumberF16,
+ isSubnormalNumberF32,
+ scalarF16Range,
+ scalarF32Range,
+} from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/bool_conversion', {
+ bool: () => {
+ return [
+ { input: bool(true), expected: bool(true) },
+ { input: bool(false), expected: bool(false) },
+ ];
+ },
+ u32: () => {
+ return fullU32Range().map(u => {
+ return { input: u32(u), expected: u === 0 ? bool(false) : bool(true) };
+ });
+ },
+ i32: () => {
+ return fullI32Range().map(i => {
+ return { input: i32(i), expected: i === 0 ? bool(false) : bool(true) };
+ });
+ },
+ f32: () => {
+ return scalarF32Range().map(f => {
+ const expected: ScalarValue[] = [];
+ if (f !== 0) {
+ expected.push(bool(true));
+ }
+ if (isSubnormalNumberF32(f)) {
+ expected.push(bool(false));
+ }
+ return { input: f32(f), expected: anyOf(...expected) };
+ });
+ },
+ f16: () => {
+ return scalarF16Range().map(f => {
+ const expected: ScalarValue[] = [];
+ if (f !== 0) {
+ expected.push(bool(true));
+ }
+ if (isSubnormalNumberF16(f)) {
+ expected.push(bool(false));
+ }
+ return { input: f16(f), expected: anyOf(...expected) };
+ });
+ },
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts
index 8fcfed339f..55d01d3eda 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts
@@ -4,78 +4,14 @@ Execution Tests for the boolean conversion operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { anyOf } from '../../../../util/compare.js';
-import {
- bool,
- f32,
- f16,
- i32,
- Scalar,
- TypeBool,
- TypeF32,
- TypeF16,
- TypeI32,
- TypeU32,
- u32,
-} from '../../../../util/conversion.js';
-import {
- fullF32Range,
- fullF16Range,
- fullI32Range,
- fullU32Range,
- isSubnormalNumberF32,
- isSubnormalNumberF16,
-} from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, run, ShaderBuilder } from '../expression.js';
+import { Type } from '../../../../util/conversion.js';
+import { ShaderBuilder, allInputSources, run } from '../expression.js';
+import { d } from './bool_conversion.cache.js';
import { unary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unary/bool_conversion', {
- bool: () => {
- return [
- { input: bool(true), expected: bool(true) },
- { input: bool(false), expected: bool(false) },
- ];
- },
- u32: () => {
- return fullU32Range().map(u => {
- return { input: u32(u), expected: u === 0 ? bool(false) : bool(true) };
- });
- },
- i32: () => {
- return fullI32Range().map(i => {
- return { input: i32(i), expected: i === 0 ? bool(false) : bool(true) };
- });
- },
- f32: () => {
- return fullF32Range().map(f => {
- const expected: Scalar[] = [];
- if (f !== 0) {
- expected.push(bool(true));
- }
- if (isSubnormalNumberF32(f)) {
- expected.push(bool(false));
- }
- return { input: f32(f), expected: anyOf(...expected) };
- });
- },
- f16: () => {
- return fullF16Range().map(f => {
- const expected: Scalar[] = [];
- if (f !== 0) {
- expected.push(bool(true));
- }
- if (isSubnormalNumberF16(f)) {
- expected.push(bool(false));
- }
- return { input: f16(f), expected: anyOf(...expected) };
- });
- },
-});
-
/** Generate expression builder based on how the test case is to be vectorized */
function vectorizeToExpression(vectorize: undefined | 2 | 3 | 4): ShaderBuilder {
return vectorize === undefined ? unary('bool') : unary(`vec${vectorize}<bool>`);
@@ -95,7 +31,14 @@ Identity operation
)
.fn(async t => {
const cases = await d.get('bool');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeBool], TypeBool, t.params, cases);
+ await run(
+ t,
+ vectorizeToExpression(t.params.vectorize),
+ [Type.bool],
+ Type.bool,
+ t.params,
+ cases
+ );
});
g.test('u32')
@@ -113,7 +56,7 @@ The result is false if e is 0, and true otherwise.
)
.fn(async t => {
const cases = await d.get('u32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeU32], TypeBool, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.u32], Type.bool, t.params, cases);
});
g.test('i32')
@@ -131,7 +74,7 @@ The result is false if e is 0, and true otherwise.
)
.fn(async t => {
const cases = await d.get('i32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeI32], TypeBool, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.i32], Type.bool, t.params, cases);
});
g.test('f32')
@@ -149,7 +92,7 @@ The result is false if e is 0.0 or -0.0, and true otherwise.
)
.fn(async t => {
const cases = await d.get('f32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeF32], TypeBool, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.f32], Type.bool, t.params, cases);
});
g.test('f16')
@@ -170,5 +113,5 @@ The result is false if e is 0.0 or -0.0, and true otherwise.
})
.fn(async t => {
const cases = await d.get('f16');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeF16], TypeBool, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.f16], Type.bool, t.params, cases);
});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_logical.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_logical.spec.ts
index 01eaaab43a..58d4b9fc0f 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_logical.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/bool_logical.spec.ts
@@ -4,7 +4,7 @@ Execution Tests for the boolean unary 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 { bool, Type } from '../../../../util/conversion.js';
import { allInputSources, run } from '../expression.js';
import { unary } from './unary.js';
@@ -29,5 +29,5 @@ Logical negation. The result is true when e is false and false when e is true. C
{ input: bool(false), expected: bool(true) },
];
- await run(t, unary('!'), [TypeBool], TypeBool, t.params, cases);
+ await run(t, unary('!'), [Type.bool], Type.bool, t.params, cases);
});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_arithmetic.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_arithmetic.cache.ts
new file mode 100644
index 0000000000..7d9ee35eec
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_arithmetic.cache.ts
@@ -0,0 +1,13 @@
+import { FP } from '../../../../util/floating_point.js';
+import { scalarF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/f16_arithmetic', {
+ negation: () => {
+ return FP.f16.generateScalarToIntervalCases(
+ scalarF16Range({ neg_norm: 250, neg_sub: 20, pos_sub: 20, pos_norm: 250 }),
+ 'unfiltered',
+ FP.f16.negationInterval
+ );
+ },
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts
index 83d7579c07..813bbf7a64 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts
@@ -4,26 +4,14 @@ Execution Tests for the f16 arithmetic unary expression operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { TypeF16 } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { fullF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
+import { Type } from '../../../../util/conversion.js';
import { allInputSources, run } from '../expression.js';
+import { d } from './f16_arithmetic.cache.js';
import { unary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unary/f16_arithmetic', {
- negation: () => {
- return FP.f16.generateScalarToIntervalCases(
- fullF16Range({ neg_norm: 250, neg_sub: 20, pos_sub: 20, pos_norm: 250 }),
- 'unfiltered',
- FP.f16.negationInterval
- );
- },
-});
-
g.test('negation')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
@@ -40,5 +28,5 @@ Accuracy: Correctly rounded
})
.fn(async t => {
const cases = await d.get('negation');
- await run(t, unary('-'), [TypeF16], TypeF16, t.params, cases);
+ await run(t, unary('-'), [Type.f16], Type.f16, t.params, cases);
});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_conversion.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_conversion.cache.ts
new file mode 100644
index 0000000000..bb0eb091dd
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_conversion.cache.ts
@@ -0,0 +1,135 @@
+import { abstractInt, bool, f16, i32, u32 } from '../../../../util/conversion.js';
+import { FP, FPInterval } from '../../../../util/floating_point.js';
+import { fullI32Range, fullI64Range, fullU32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const f16FiniteRangeInterval = new FPInterval(
+ 'f16',
+ FP.f16.constants().negative.min,
+ FP.f16.constants().positive.max
+);
+
+// Cases: f32_matCxR_[non_]const
+// Note that f32 values may be not exactly representable in f16 and/or out of range.
+const f32_mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`f32_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateMatrixToMatrixCases(
+ FP.f32.sparseMatrixRange(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.correctlyRoundedMatrix
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: f16_matCxR_[non_]const
+const f16_mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`f16_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ // Input matrix is of f16 types, use f16.generateMatrixToMatrixCases.
+ return FP.f16.generateMatrixToMatrixCases(
+ FP.f16.sparseMatrixRange(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.correctlyRoundedMatrix
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: abstract_float_matCxR
+// Note that abstract float values may be not exactly representable in f16
+// and/or out of range.
+const abstract_float_mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).map(rows => ({
+ [`abstract_float_mat${cols}x${rows}`]: () => {
+ return FP.abstract.generateMatrixToMatrixCases(
+ FP.abstract.sparseMatrixRange(cols, rows),
+ 'finite',
+ FP.f16.correctlyRoundedMatrix
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('unary/f16_conversion', {
+ bool: () => {
+ return [
+ { input: bool(true), expected: f16(1.0) },
+ { input: bool(false), expected: f16(0.0) },
+ ];
+ },
+ u32_non_const: () => {
+ return [...fullU32Range(), 65504].map(u => {
+ return { input: u32(u), expected: FP.f16.correctlyRoundedInterval(u) };
+ });
+ },
+ u32_const: () => {
+ return [...fullU32Range(), 65504]
+ .filter(v => f16FiniteRangeInterval.contains(v))
+ .map(u => {
+ return { input: u32(u), expected: FP.f16.correctlyRoundedInterval(u) };
+ });
+ },
+ i32_non_const: () => {
+ return [...fullI32Range(), 65504, -65504].map(i => {
+ return { input: i32(i), expected: FP.f16.correctlyRoundedInterval(i) };
+ });
+ },
+ i32_const: () => {
+ return [...fullI32Range(), 65504, -65504]
+ .filter(v => f16FiniteRangeInterval.contains(v))
+ .map(i => {
+ return { input: i32(i), expected: FP.f16.correctlyRoundedInterval(i) };
+ });
+ },
+ abstract_int: () => {
+ return [...fullI64Range(), 65504n, -65504n]
+ .filter(v => f16FiniteRangeInterval.contains(Number(v)))
+ .map(i => {
+ return { input: abstractInt(i), expected: FP.f16.correctlyRoundedInterval(Number(i)) };
+ });
+ },
+ // Note that f32 values may be not exactly representable in f16 and/or out of range.
+ f32_non_const: () => {
+ return FP.f32.generateScalarToIntervalCases(
+ [...FP.f32.scalarRange(), 65535.996, -65535.996],
+ 'unfiltered',
+ FP.f16.correctlyRoundedInterval
+ );
+ },
+ f32_const: () => {
+ return FP.f32.generateScalarToIntervalCases(
+ [...FP.f32.scalarRange(), 65535.996, -65535.996],
+ 'finite',
+ FP.f16.correctlyRoundedInterval
+ );
+ },
+ // Note that abstract float values may be not exactly representable in f16.
+ abstract_float: () => {
+ return FP.abstract.generateScalarToIntervalCases(
+ [...FP.abstract.scalarRange(), 65535.996, -65535.996],
+ 'finite',
+ FP.f16.correctlyRoundedInterval
+ );
+ },
+ // All f16 values are exactly representable in f16.
+ f16: () => {
+ return FP.f16.scalarRange().map(f => {
+ return { input: f16(f), expected: FP.f16.correctlyRoundedInterval(f) };
+ });
+ },
+ ...f32_mat_cases,
+ ...f16_mat_cases,
+ ...abstract_float_mat_cases,
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts
index 9eb84f0270..92bd9c6a07 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts
@@ -4,132 +4,14 @@ Execution Tests for the f32 conversion operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import {
- bool,
- f16,
- i32,
- TypeBool,
- TypeF32,
- TypeF16,
- TypeI32,
- TypeMat,
- TypeU32,
- u32,
-} from '../../../../util/conversion.js';
-import { FP, FPInterval } from '../../../../util/floating_point.js';
-import {
- fullF32Range,
- fullF16Range,
- fullI32Range,
- fullU32Range,
- sparseMatrixF32Range,
- sparseMatrixF16Range,
-} from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, run, ShaderBuilder } from '../expression.js';
+import { Type } from '../../../../util/conversion.js';
+import { ShaderBuilder, allInputSources, run, onlyConstInputSource } from '../expression.js';
+import { d } from './f16_conversion.cache.js';
import { unary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-const f16FiniteRangeInterval = new FPInterval(
- 'f32',
- FP.f16.constants().negative.min,
- FP.f16.constants().positive.max
-);
-
-// Cases: f32_matCxR_[non_]const
-// Note that f32 values may be not exactly representable in f16 and/or out of range.
-const f32_mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`f32_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateMatrixToMatrixCases(
- sparseMatrixF32Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.correctlyRoundedMatrix
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: f16_matCxR_[non_]const
-const f16_mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`f16_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- // Input matrix is of f16 types, use f16.generateMatrixToMatrixCases.
- return FP.f16.generateMatrixToMatrixCases(
- sparseMatrixF16Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.correctlyRoundedMatrix
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('unary/f16_conversion', {
- bool: () => {
- return [
- { input: bool(true), expected: f16(1.0) },
- { input: bool(false), expected: f16(0.0) },
- ];
- },
- u32_non_const: () => {
- return [...fullU32Range(), 65504].map(u => {
- return { input: u32(u), expected: FP.f16.correctlyRoundedInterval(u) };
- });
- },
- u32_const: () => {
- return [...fullU32Range(), 65504]
- .filter(v => f16FiniteRangeInterval.contains(v))
- .map(u => {
- return { input: u32(u), expected: FP.f16.correctlyRoundedInterval(u) };
- });
- },
- i32_non_const: () => {
- return [...fullI32Range(), 65504, -65504].map(i => {
- return { input: i32(i), expected: FP.f16.correctlyRoundedInterval(i) };
- });
- },
- i32_const: () => {
- return [...fullI32Range(), 65504, -65504]
- .filter(v => f16FiniteRangeInterval.contains(v))
- .map(i => {
- return { input: i32(i), expected: FP.f16.correctlyRoundedInterval(i) };
- });
- },
- // Note that f32 values may be not exactly representable in f16 and/or out of range.
- f32_non_const: () => {
- return FP.f32.generateScalarToIntervalCases(
- [...fullF32Range(), 65535.996, -65535.996],
- 'unfiltered',
- FP.f16.correctlyRoundedInterval
- );
- },
- f32_const: () => {
- return FP.f32.generateScalarToIntervalCases(
- [...fullF32Range(), 65535.996, -65535.996],
- 'finite',
- FP.f16.correctlyRoundedInterval
- );
- },
- // All f16 values are exactly representable in f16.
- f16: () => {
- return fullF16Range().map(f => {
- return { input: f16(f), expected: FP.f16.correctlyRoundedInterval(f) };
- });
- },
- ...f32_mat_cases,
- ...f16_mat_cases,
-});
-
/** Generate a ShaderBuilder based on how the test case is to be vectorized */
function vectorizeToExpression(vectorize: undefined | 2 | 3 | 4): ShaderBuilder {
return vectorize === undefined ? unary('f16') : unary(`vec${vectorize}<f16>`);
@@ -157,7 +39,7 @@ The result is 1.0 if e is true and 0.0 otherwise
})
.fn(async t => {
const cases = await d.get('bool');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeBool], TypeF16, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.bool], Type.f16, t.params, cases);
});
g.test('u32')
@@ -177,7 +59,7 @@ Converted to f16, +/-Inf if out of range
})
.fn(async t => {
const cases = await d.get(t.params.inputSource === 'const' ? 'u32_const' : 'u32_non_const');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeU32], TypeF16, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.u32], Type.f16, t.params, cases);
});
g.test('i32')
@@ -197,7 +79,36 @@ Converted to f16, +/-Inf if out of range
})
.fn(async t => {
const cases = await d.get(t.params.inputSource === 'const' ? 'i32_const' : 'i32_non_const');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeI32], TypeF16, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.i32], Type.f16, t.params, cases);
+ });
+
+g.test('abstract_int')
+ .specURL('https://www.w3.org/TR/WGSL/#value-constructor-builtin-function')
+ .desc(
+ `
+f16(e), where e is an AbstractInt
+
+Converted to f16, +/-Inf if out of range
+`
+ )
+ .params(u =>
+ u
+ .combine('inputSource', onlyConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ )
+ .beforeAllSubcases(t => {
+ t.selectDeviceOrSkipTestCase({ requiredFeatures: ['shader-f16'] });
+ })
+ .fn(async t => {
+ const cases = await d.get('abstract_int');
+ await run(
+ t,
+ vectorizeToExpression(t.params.vectorize),
+ [Type.abstractInt],
+ Type.f16,
+ t.params,
+ cases
+ );
});
g.test('f32')
@@ -217,7 +128,7 @@ Correctly rounded to f16
})
.fn(async t => {
const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeF32], TypeF16, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.f32], Type.f16, t.params, cases);
});
g.test('f32_mat')
@@ -243,8 +154,8 @@ g.test('f32_mat')
await run(
t,
matrixExperession(cols, rows),
- [TypeMat(cols, rows, TypeF32)],
- TypeMat(cols, rows, TypeF16),
+ [Type.mat(cols, rows, Type.f32)],
+ Type.mat(cols, rows, Type.f16),
t.params,
cases
);
@@ -267,7 +178,7 @@ g.test('f16')
})
.fn(async t => {
const cases = await d.get('f16');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeF16], TypeF16, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.f16], Type.f16, t.params, cases);
});
g.test('f16_mat')
@@ -293,8 +204,63 @@ g.test('f16_mat')
await run(
t,
matrixExperession(cols, rows),
- [TypeMat(cols, rows, TypeF16)],
- TypeMat(cols, rows, TypeF16),
+ [Type.mat(cols, rows, Type.f16)],
+ Type.mat(cols, rows, Type.f16),
+ t.params,
+ cases
+ );
+ });
+
+g.test('abstract_float')
+ .specURL('https://www.w3.org/TR/WGSL/#value-constructor-builtin-function')
+ .desc(
+ `
+f16(e), where e is an AbstractFloat
+
+Correctly rounded to f16
+`
+ )
+ .params(u =>
+ u
+ .combine('inputSource', onlyConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ )
+ .beforeAllSubcases(t => {
+ t.selectDeviceOrSkipTestCase({ requiredFeatures: ['shader-f16'] });
+ })
+ .fn(async t => {
+ const cases = await d.get('abstract_float');
+ await run(
+ t,
+ vectorizeToExpression(t.params.vectorize),
+ [Type.abstractFloat],
+ Type.f16,
+ t.params,
+ cases
+ );
+ });
+
+g.test('abstract_float_mat')
+ .specURL('https://www.w3.org/TR/WGSL/#matrix-builtin-functions')
+ .desc(`AbstractFloat matrix to f16 matrix tests`)
+ .params(u =>
+ u
+ .combine('inputSource', onlyConstInputSource)
+ .combine('cols', [2, 3, 4] as const)
+ .combine('rows', [2, 3, 4] as const)
+ )
+ .beforeAllSubcases(t => {
+ t.selectDeviceOrSkipTestCase({ requiredFeatures: ['shader-f16'] });
+ })
+ .fn(async t => {
+ const cols = t.params.cols;
+ const rows = t.params.rows;
+ const cases = await d.get(`abstract_float_mat${cols}x${rows}`);
+ await run(
+ t,
+ matrixExperession(cols, rows),
+ [Type.mat(cols, rows, Type.abstractFloat)],
+ Type.mat(cols, rows, Type.f16),
t.params,
cases
);
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_arithmetic.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_arithmetic.cache.ts
new file mode 100644
index 0000000000..b23ed3216b
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_arithmetic.cache.ts
@@ -0,0 +1,13 @@
+import { FP } from '../../../../util/floating_point.js';
+import { scalarF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/f32_arithmetic', {
+ negation: () => {
+ return FP.f32.generateScalarToIntervalCases(
+ scalarF32Range({ neg_norm: 250, neg_sub: 20, pos_sub: 20, pos_norm: 250 }),
+ 'unfiltered',
+ FP.f32.negationInterval
+ );
+ },
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts
index f53cff46d8..3bb48705e8 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts
@@ -4,26 +4,14 @@ Execution Tests for the f32 arithmetic unary expression operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { TypeF32 } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { fullF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
+import { Type } from '../../../../util/conversion.js';
import { allInputSources, run } from '../expression.js';
+import { d } from './f32_arithmetic.cache.js';
import { unary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unary/f32_arithmetic', {
- negation: () => {
- return FP.f32.generateScalarToIntervalCases(
- fullF32Range({ neg_norm: 250, neg_sub: 20, pos_sub: 20, pos_norm: 250 }),
- 'unfiltered',
- FP.f32.negationInterval
- );
- },
-});
-
g.test('negation')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
@@ -37,5 +25,5 @@ Accuracy: Correctly rounded
)
.fn(async t => {
const cases = await d.get('negation');
- await run(t, unary('-'), [TypeF32], TypeF32, t.params, cases);
+ await run(t, unary('-'), [Type.f32], Type.f32, t.params, cases);
});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_conversion.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_conversion.cache.ts
new file mode 100644
index 0000000000..f61435f07c
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_conversion.cache.ts
@@ -0,0 +1,79 @@
+import { bool, f16, f32, i32, u32 } from '../../../../util/conversion.js';
+import { FP } from '../../../../util/floating_point.js';
+import {
+ fullI32Range,
+ fullU32Range,
+ scalarF16Range,
+ scalarF32Range,
+ sparseMatrixF16Range,
+ sparseMatrixF32Range,
+} from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: f32_matCxR_[non_]const
+const f32_mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`f32_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateMatrixToMatrixCases(
+ sparseMatrixF32Range(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.correctlyRoundedMatrix
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: f16_matCxR_[non_]const
+// Note that all f16 values are exactly representable in f32.
+const f16_mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`f16_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ // Input matrix is of f16 types, use f16.generateMatrixToMatrixCases.
+ return FP.f16.generateMatrixToMatrixCases(
+ sparseMatrixF16Range(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.correctlyRoundedMatrix
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('unary/f32_conversion', {
+ bool: () => {
+ return [
+ { input: bool(true), expected: f32(1.0) },
+ { input: bool(false), expected: f32(0.0) },
+ ];
+ },
+ u32: () => {
+ return fullU32Range().map(u => {
+ return { input: u32(u), expected: FP.f32.correctlyRoundedInterval(u) };
+ });
+ },
+ i32: () => {
+ return fullI32Range().map(i => {
+ return { input: i32(i), expected: FP.f32.correctlyRoundedInterval(i) };
+ });
+ },
+ f32: () => {
+ return scalarF32Range().map(f => {
+ return { input: f32(f), expected: FP.f32.correctlyRoundedInterval(f) };
+ });
+ },
+ // All f16 values are exactly representable in f32.
+ f16: () => {
+ return scalarF16Range().map(f => {
+ return { input: f16(f), expected: FP.f32.correctlyRoundedInterval(f) };
+ });
+ },
+ ...f32_mat_cases,
+ ...f16_mat_cases,
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts
index 223b13c2d5..464fdee44e 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts
@@ -4,103 +4,14 @@ Execution Tests for the f32 conversion operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import {
- bool,
- f32,
- f16,
- i32,
- TypeBool,
- TypeF32,
- TypeF16,
- TypeI32,
- TypeMat,
- TypeU32,
- u32,
-} from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import {
- fullF32Range,
- fullF16Range,
- fullI32Range,
- fullU32Range,
- sparseMatrixF32Range,
- sparseMatrixF16Range,
-} from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, run, ShaderBuilder } from '../expression.js';
+import { Type } from '../../../../util/conversion.js';
+import { ShaderBuilder, allInputSources, run } from '../expression.js';
+import { d } from './f32_conversion.cache.js';
import { unary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-// Cases: f32_matCxR_[non_]const
-const f32_mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`f32_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateMatrixToMatrixCases(
- sparseMatrixF32Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.correctlyRoundedMatrix
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: f16_matCxR_[non_]const
-// Note that all f16 values are exactly representable in f32.
-const f16_mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`f16_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- // Input matrix is of f16 types, use f16.generateMatrixToMatrixCases.
- return FP.f16.generateMatrixToMatrixCases(
- sparseMatrixF16Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.correctlyRoundedMatrix
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('unary/f32_conversion', {
- bool: () => {
- return [
- { input: bool(true), expected: f32(1.0) },
- { input: bool(false), expected: f32(0.0) },
- ];
- },
- u32: () => {
- return fullU32Range().map(u => {
- return { input: u32(u), expected: FP.f32.correctlyRoundedInterval(u) };
- });
- },
- i32: () => {
- return fullI32Range().map(i => {
- return { input: i32(i), expected: FP.f32.correctlyRoundedInterval(i) };
- });
- },
- f32: () => {
- return fullF32Range().map(f => {
- return { input: f32(f), expected: FP.f32.correctlyRoundedInterval(f) };
- });
- },
- // All f16 values are exactly representable in f32.
- f16: () => {
- return fullF16Range().map(f => {
- return { input: f16(f), expected: FP.f32.correctlyRoundedInterval(f) };
- });
- },
- ...f32_mat_cases,
- ...f16_mat_cases,
-});
-
/** Generate a ShaderBuilder based on how the test case is to be vectorized */
function vectorizeToExpression(vectorize: undefined | 2 | 3 | 4): ShaderBuilder {
return vectorize === undefined ? unary('f32') : unary(`vec${vectorize}<f32>`);
@@ -125,7 +36,7 @@ The result is 1.0 if e is true and 0.0 otherwise
)
.fn(async t => {
const cases = await d.get('bool');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeBool], TypeF32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.bool], Type.f32, t.params, cases);
});
g.test('u32')
@@ -142,7 +53,7 @@ Converted to f32
)
.fn(async t => {
const cases = await d.get('u32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeU32], TypeF32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.u32], Type.f32, t.params, cases);
});
g.test('i32')
@@ -159,7 +70,7 @@ Converted to f32
)
.fn(async t => {
const cases = await d.get('i32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeI32], TypeF32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.i32], Type.f32, t.params, cases);
});
g.test('f32')
@@ -176,7 +87,7 @@ Identity operation
)
.fn(async t => {
const cases = await d.get('f32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeF32], TypeF32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.f32], Type.f32, t.params, cases);
});
g.test('f32_mat')
@@ -199,8 +110,8 @@ g.test('f32_mat')
await run(
t,
matrixExperession(cols, rows),
- [TypeMat(cols, rows, TypeF32)],
- TypeMat(cols, rows, TypeF32),
+ [Type.mat(cols, rows, Type.f32)],
+ Type.mat(cols, rows, Type.f32),
t.params,
cases
);
@@ -223,7 +134,7 @@ g.test('f16')
})
.fn(async t => {
const cases = await d.get('f16');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeF16], TypeF32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.f16], Type.f32, t.params, cases);
});
g.test('f16_mat')
@@ -249,8 +160,8 @@ g.test('f16_mat')
await run(
t,
matrixExperession(cols, rows),
- [TypeMat(cols, rows, TypeF16)],
- TypeMat(cols, rows, TypeF32),
+ [Type.mat(cols, rows, Type.f16)],
+ Type.mat(cols, rows, Type.f32),
t.params,
cases
);
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_arithmetic.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_arithmetic.cache.ts
new file mode 100644
index 0000000000..b7206bcf45
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_arithmetic.cache.ts
@@ -0,0 +1,11 @@
+import { i32 } from '../../../../util/conversion.js';
+import { fullI32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/i32_arithmetic', {
+ negation: () => {
+ return fullI32Range().map(e => {
+ return { input: i32(e), expected: i32(-e) };
+ });
+ },
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts
index 14519b8967..a7d16a96cd 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts
@@ -4,23 +4,14 @@ Execution Tests for the i32 arithmetic unary expression operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { i32, TypeI32 } from '../../../../util/conversion.js';
-import { fullI32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
+import { Type } from '../../../../util/conversion.js';
import { allInputSources, run } from '../expression.js';
+import { d } from './i32_arithmetic.cache.js';
import { unary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unary/i32_arithmetic', {
- negation: () => {
- return fullI32Range().map(e => {
- return { input: i32(e), expected: i32(-e) };
- });
- },
-});
-
g.test('negation')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
@@ -33,5 +24,5 @@ Expression: -x
)
.fn(async t => {
const cases = await d.get('negation');
- await run(t, unary('-'), [TypeI32], TypeI32, t.params, cases);
+ await run(t, unary('-'), [Type.i32], Type.i32, t.params, cases);
});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts
index e8bda51b51..01e5728d70 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts
@@ -4,23 +4,14 @@ Execution Tests for the i32 bitwise complement operation
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { i32, TypeI32 } from '../../../../util/conversion.js';
+import { i32, Type } from '../../../../util/conversion.js';
import { fullI32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { unary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unary/i32_complement', {
- complement: () => {
- return fullI32Range().map(e => {
- return { input: i32(e), expected: i32(~e) };
- });
- },
-});
-
g.test('i32_complement')
.specURL('https://www.w3.org/TR/WGSL/#bit-expr')
.desc(
@@ -32,6 +23,8 @@ Expression: ~x
u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const)
)
.fn(async t => {
- const cases = await d.get('complement');
- await run(t, unary('~'), [TypeI32], TypeI32, t.params, cases);
+ const cases = fullI32Range().map(e => {
+ return { input: i32(e), expected: i32(~e) };
+ });
+ await run(t, unary('~'), [Type.i32], Type.i32, t.params, cases);
});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_conversion.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_conversion.cache.ts
new file mode 100644
index 0000000000..1c2d01548d
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_conversion.cache.ts
@@ -0,0 +1,116 @@
+import { kValue } from '../../../../util/constants.js';
+import {
+ abstractFloat,
+ abstractInt,
+ bool,
+ f16,
+ f32,
+ i32,
+ u32,
+} from '../../../../util/conversion.js';
+import {
+ fullI32Range,
+ fullU32Range,
+ quantizeToF16,
+ quantizeToF32,
+ scalarF16Range,
+ scalarF32Range,
+ scalarF64Range,
+} from '../../../../util/math.js';
+import { reinterpretU32AsI32 } from '../../../../util/reinterpret.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/i32_conversion', {
+ bool: () => {
+ return [
+ { input: bool(true), expected: i32(1) },
+ { input: bool(false), expected: i32(0) },
+ ];
+ },
+ abstractInt: () => {
+ return fullI32Range().map(i => {
+ return { input: abstractInt(BigInt(i)), expected: i32(i) };
+ });
+ },
+ u32: () => {
+ return fullU32Range().map(u => {
+ return { input: u32(u), expected: i32(reinterpretU32AsI32(u)) };
+ });
+ },
+ i32: () => {
+ return fullI32Range().map(i => {
+ return { input: i32(i), expected: i32(i) };
+ });
+ },
+ abstractFloat: () => {
+ return scalarF64Range().map(f => {
+ // Handles zeros and subnormals
+ if (Math.abs(f) < 1.0) {
+ return { input: abstractFloat(f), expected: i32(0) };
+ }
+
+ if (f <= kValue.i32.negative.min) {
+ return { input: abstractFloat(f), expected: i32(kValue.i32.negative.min) };
+ }
+
+ if (f >= kValue.i32.positive.max) {
+ return { input: abstractFloat(f), expected: i32(kValue.i32.positive.max) };
+ }
+
+ // All i32s are representable as f64, and both AbstractFloat and number
+ // are f64 internally, so there is no need for special casing like f32 and
+ // f16 below.
+ return { input: abstractFloat(f), expected: i32(Math.trunc(f)) };
+ });
+ },
+ f32: () => {
+ return scalarF32Range().map(f => {
+ // Handles zeros and subnormals
+ if (Math.abs(f) < 1.0) {
+ return { input: f32(f), expected: i32(0) };
+ }
+
+ if (f <= kValue.i32.negative.min) {
+ return { input: f32(f), expected: i32(kValue.i32.negative.min) };
+ }
+
+ if (f >= kValue.i32.positive.max) {
+ return { input: f32(f), expected: i32(kValue.i32.positive.max) };
+ }
+
+ // All f32 no larger than 2^24 has a precise interger part and a fractional part, just need
+ // to trunc towards 0 for the result integer.
+ if (Math.abs(f) <= 2 ** 24) {
+ return { input: f32(f), expected: i32(Math.trunc(f)) };
+ }
+
+ // All f32s between 2 ** 24 and kValue.i32.negative.min/.positive.max are
+ // integers, so in theory one could use them directly, expect that number
+ // is actually f64 internally, so they need to be quantized to f32 first.
+ // Cannot just use trunc here, since that might produce a i32 value that
+ // is precise in f64, but not in f32.
+ return { input: f32(f), expected: i32(quantizeToF32(f)) };
+ });
+ },
+ f16: () => {
+ // Note that finite f16 values are always in range of i32.
+ return scalarF16Range().map(f => {
+ // Handles zeros and subnormals
+ if (Math.abs(f) < 1.0) {
+ return { input: f16(f), expected: i32(0) };
+ }
+
+ // All f16 no larger than <= 2^12 has a precise interger part and a fractional part, just need
+ // to trunc towards 0 for the result integer.
+ if (Math.abs(f) <= 2 ** 12) {
+ return { input: f16(f), expected: i32(Math.trunc(f)) };
+ }
+
+ // All f16s larger than 2 ** 12 are integers, so in theory one could use them directly, expect
+ // that number is actually f64 internally, so they need to be quantized to f16 first.
+ // Cannot just use trunc here, since that might produce a i32 value that is precise in f64,
+ // but not in f16.
+ return { input: f16(f), expected: i32(quantizeToF16(f)) };
+ });
+ },
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts
index a77aa0e4d3..b47ffe0d07 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts
@@ -4,104 +4,14 @@ Execution Tests for the i32 conversion operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { kValue } from '../../../../util/constants.js';
-import {
- bool,
- f32,
- f16,
- i32,
- TypeBool,
- TypeF32,
- TypeF16,
- TypeI32,
- TypeU32,
- u32,
-} from '../../../../util/conversion.js';
-import {
- fullF32Range,
- fullF16Range,
- fullI32Range,
- fullU32Range,
- quantizeToF32,
- quantizeToF16,
-} from '../../../../util/math.js';
-import { reinterpretU32AsI32 } from '../../../../util/reinterpret.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, run, ShaderBuilder } from '../expression.js';
+import { Type } from '../../../../util/conversion.js';
+import { ShaderBuilder, allInputSources, run, onlyConstInputSource } from '../expression.js';
+import { d } from './i32_conversion.cache.js';
import { unary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unary/i32_conversion', {
- bool: () => {
- return [
- { input: bool(true), expected: i32(1) },
- { input: bool(false), expected: i32(0) },
- ];
- },
- u32: () => {
- return fullU32Range().map(u => {
- return { input: u32(u), expected: i32(reinterpretU32AsI32(u)) };
- });
- },
- i32: () => {
- return fullI32Range().map(i => {
- return { input: i32(i), expected: i32(i) };
- });
- },
- f32: () => {
- return fullF32Range().map(f => {
- // Handles zeros and subnormals
- if (Math.abs(f) < 1.0) {
- return { input: f32(f), expected: i32(0) };
- }
-
- if (f <= kValue.i32.negative.min) {
- return { input: f32(f), expected: i32(kValue.i32.negative.min) };
- }
-
- if (f >= kValue.i32.positive.max) {
- return { input: f32(f), expected: i32(kValue.i32.positive.max) };
- }
-
- // All f32 no larger than 2^24 has a precise interger part and a fractional part, just need
- // to trunc towards 0 for the result integer.
- if (Math.abs(f) <= 2 ** 24) {
- return { input: f32(f), expected: i32(Math.trunc(f)) };
- }
-
- // All f32s between 2 ** 24 and kValue.i32.negative.min/.positive.max are
- // integers, so in theory one could use them directly, expect that number
- // is actually f64 internally, so they need to be quantized to f32 first.
- // Cannot just use trunc here, since that might produce a i32 value that
- // is precise in f64, but not in f32.
- return { input: f32(f), expected: i32(quantizeToF32(f)) };
- });
- },
- f16: () => {
- // Note that finite f16 values are always in range of i32.
- return fullF16Range().map(f => {
- // Handles zeros and subnormals
- if (Math.abs(f) < 1.0) {
- return { input: f16(f), expected: i32(0) };
- }
-
- // All f16 no larger than <= 2^12 has a precise interger part and a fractional part, just need
- // to trunc towards 0 for the result integer.
- if (Math.abs(f) <= 2 ** 12) {
- return { input: f16(f), expected: i32(Math.trunc(f)) };
- }
-
- // All f16s larger than 2 ** 12 are integers, so in theory one could use them directly, expect
- // that number is actually f64 internally, so they need to be quantized to f16 first.
- // Cannot just use trunc here, since that might produce a i32 value that is precise in f64,
- // but not in f16.
- return { input: f16(f), expected: i32(quantizeToF16(f)) };
- });
- },
-});
-
/** Generate a ShaderBuilder based on how the test case is to be vectorized */
function vectorizeToExpression(vectorize: undefined | 2 | 3 | 4): ShaderBuilder {
return vectorize === undefined ? unary('i32') : unary(`vec${vectorize}<i32>`);
@@ -121,7 +31,7 @@ The result is 1u if e is true and 0u otherwise
)
.fn(async t => {
const cases = await d.get('bool');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeBool], TypeI32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.bool], Type.i32, t.params, cases);
});
g.test('u32')
@@ -138,7 +48,7 @@ Reinterpretation of bits
)
.fn(async t => {
const cases = await d.get('u32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeU32], TypeI32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.u32], Type.i32, t.params, cases);
});
g.test('i32')
@@ -155,7 +65,7 @@ Identity operation
)
.fn(async t => {
const cases = await d.get('i32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeI32], TypeI32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.i32], Type.i32, t.params, cases);
});
g.test('f32')
@@ -172,7 +82,7 @@ e is converted to i32, rounding towards zero
)
.fn(async t => {
const cases = await d.get('f32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeF32], TypeI32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.f32], Type.i32, t.params, cases);
});
g.test('f16')
@@ -192,5 +102,57 @@ e is converted to u32, rounding towards zero
})
.fn(async t => {
const cases = await d.get('f16');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeF16], TypeI32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.f16], Type.i32, t.params, cases);
+ });
+
+g.test('abstract_int')
+ .specURL('https://www.w3.org/TR/WGSL/#value-constructor-builtin-function')
+ .desc(
+ `
+i32(e), where e is an AbstractInt
+
+Identity operation if e is in bounds for i32, otherwise shader creation error
+`
+ )
+ .params(u =>
+ u
+ .combine('inputSource', onlyConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ )
+ .fn(async t => {
+ const cases = await d.get('abstractInt');
+ await run(
+ t,
+ vectorizeToExpression(t.params.vectorize),
+ [Type.abstractInt],
+ Type.i32,
+ t.params,
+ cases
+ );
+ });
+
+g.test('abstract_float')
+ .specURL('https://www.w3.org/TR/WGSL/#value-constructor-builtin-function')
+ .desc(
+ `
+i32(e), where e is an AbstractFloat
+
+e is converted to i32, rounding towards zero
+`
+ )
+ .params(u =>
+ u
+ .combine('inputSource', onlyConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ )
+ .fn(async t => {
+ const cases = await d.get('abstractFloat');
+ await run(
+ t,
+ vectorizeToExpression(t.params.vectorize),
+ [Type.abstractFloat],
+ Type.i32,
+ t.params,
+ cases
+ );
});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts
index 446e0918bd..74251a32c6 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts
@@ -4,23 +4,14 @@ Execution Tests for the u32 bitwise complement operation
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { u32, TypeU32 } from '../../../../util/conversion.js';
+import { Type, u32 } from '../../../../util/conversion.js';
import { fullU32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { unary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unary/u32_complement', {
- complement: () => {
- return fullU32Range().map(e => {
- return { input: u32(e), expected: u32(~e) };
- });
- },
-});
-
g.test('u32_complement')
.specURL('https://www.w3.org/TR/WGSL/#bit-expr')
.desc(
@@ -32,6 +23,8 @@ Expression: ~x
u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const)
)
.fn(async t => {
- const cases = await d.get('complement');
- await run(t, unary('~'), [TypeU32], TypeU32, t.params, cases);
+ const cases = fullU32Range().map(e => {
+ return { input: u32(e), expected: u32(~e) };
+ });
+ await run(t, unary('~'), [Type.u32], Type.u32, t.params, cases);
});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_conversion.cache.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_conversion.cache.ts
new file mode 100644
index 0000000000..1ef307810f
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_conversion.cache.ts
@@ -0,0 +1,107 @@
+import { kValue } from '../../../../util/constants.js';
+import {
+ abstractFloat,
+ abstractInt,
+ bool,
+ f16,
+ f32,
+ i32,
+ u32,
+} from '../../../../util/conversion.js';
+import {
+ fullI32Range,
+ fullU32Range,
+ quantizeToF16,
+ quantizeToF32,
+ scalarF16Range,
+ scalarF32Range,
+ scalarF64Range,
+} from '../../../../util/math.js';
+import { reinterpretI32AsU32 } from '../../../../util/reinterpret.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/u32_conversion', {
+ bool: () => {
+ return [
+ { input: bool(true), expected: u32(1) },
+ { input: bool(false), expected: u32(0) },
+ ];
+ },
+ abstractInt: () => {
+ return fullU32Range().map(u => {
+ return { input: abstractInt(BigInt(u)), expected: u32(u) };
+ });
+ },
+ u32: () => {
+ return fullU32Range().map(u => {
+ return { input: u32(u), expected: u32(u) };
+ });
+ },
+ i32: () => {
+ return fullI32Range().map(i => {
+ return { input: i32(i), expected: u32(reinterpretI32AsU32(i)) };
+ });
+ },
+ abstractFloat: () => {
+ return [...scalarF64Range(), -1].map(f => {
+ // Handles zeros, subnormals, and negatives
+ if (f < 1.0) {
+ return { input: abstractFloat(f), expected: u32(0) };
+ }
+
+ if (f >= kValue.u32.max) {
+ return { input: abstractFloat(f), expected: u32(kValue.u32.max) };
+ }
+
+ // All u32s are representable as f64s and number is a f64 internally, so
+ // no need for special handling like is done for f32 and f16 below.
+ return { input: abstractFloat(f), expected: u32(Math.floor(f)) };
+ });
+ },
+ f32: () => {
+ return scalarF32Range().map(f => {
+ // Handles zeros, subnormals, and negatives
+ if (f < 1.0) {
+ return { input: f32(f), expected: u32(0) };
+ }
+
+ if (f >= kValue.u32.max) {
+ return { input: f32(f), expected: u32(kValue.u32.max) };
+ }
+
+ // All f32 no larger than 2^24 has a precise integer part and a fractional
+ // part, just need to trunc towards 0 for the result integer.
+ if (f <= 2 ** 24) {
+ return { input: f32(f), expected: u32(Math.floor(f)) };
+ }
+
+ // All f32s between 2 ** 24 and kValue.u32.max are integers, so in theory
+ // one could use them directly, expect that number is actually f64
+ // internally, so they need to be quantized to f32 first.
+ // Cannot just use floor here, since that might produce a u32 value that
+ // is precise in f64, but not in f32.
+ return { input: f32(f), expected: u32(quantizeToF32(f)) };
+ });
+ },
+ f16: () => {
+ // Note that all positive finite f16 values are in range of u32.
+ return scalarF16Range().map(f => {
+ // Handles zeros, subnormals, and negatives
+ if (f < 1.0) {
+ return { input: f16(f), expected: u32(0) };
+ }
+
+ // All f16 no larger than <= 2^12 has a precise integer part and a
+ // fractional part, just need to trunc towards 0 for the result integer.
+ if (f <= 2 ** 12) {
+ return { input: f16(f), expected: u32(Math.trunc(f)) };
+ }
+
+ // All f16s larger than 2 ** 12 are integers, so in theory one could use
+ // them directly, expect that number is actually f64 internally, so they
+ // need to be quantized to f16 first.Cannot just use trunc here, since
+ // that might produce a u32 value that is precise in f64, but not in f16.
+ return { input: f16(f), expected: u32(quantizeToF16(f)) };
+ });
+ },
+});
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts
index 87dc6e7a5d..6d342afffb 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts
@@ -4,100 +4,14 @@ Execution Tests for the u32 conversion operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { kValue } from '../../../../util/constants.js';
-import {
- bool,
- f32,
- f16,
- i32,
- TypeBool,
- TypeF32,
- TypeF16,
- TypeI32,
- TypeU32,
- u32,
-} from '../../../../util/conversion.js';
-import {
- fullF32Range,
- fullF16Range,
- fullI32Range,
- fullU32Range,
- quantizeToF32,
- quantizeToF16,
-} from '../../../../util/math.js';
-import { reinterpretI32AsU32 } from '../../../../util/reinterpret.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, run, ShaderBuilder } from '../expression.js';
+import { Type } from '../../../../util/conversion.js';
+import { ShaderBuilder, allInputSources, run, onlyConstInputSource } from '../expression.js';
+import { d } from './u32_conversion.cache.js';
import { unary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unary/u32_conversion', {
- bool: () => {
- return [
- { input: bool(true), expected: u32(1) },
- { input: bool(false), expected: u32(0) },
- ];
- },
- u32: () => {
- return fullU32Range().map(u => {
- return { input: u32(u), expected: u32(u) };
- });
- },
- i32: () => {
- return fullI32Range().map(i => {
- return { input: i32(i), expected: u32(reinterpretI32AsU32(i)) };
- });
- },
- f32: () => {
- return fullF32Range().map(f => {
- // Handles zeros, subnormals, and negatives
- if (f < 1.0) {
- return { input: f32(f), expected: u32(0) };
- }
-
- if (f >= kValue.u32.max) {
- return { input: f32(f), expected: u32(kValue.u32.max) };
- }
-
- // All f32 no larger than 2^24 has a precise interger part and a fractional part, just need
- // to trunc towards 0 for the result integer.
- if (f <= 2 ** 24) {
- return { input: f32(f), expected: u32(Math.floor(f)) };
- }
-
- // All f32s between 2 ** 24 and kValue.u32.max are integers, so in theory
- // one could use them directly, expect that number is actually f64
- // internally, so they need to be quantized to f32 first.
- // Cannot just use floor here, since that might produce a u32 value that
- // is precise in f64, but not in f32.
- return { input: f32(f), expected: u32(quantizeToF32(f)) };
- });
- },
- f16: () => {
- // Note that all positive finite f16 values are in range of u32.
- return fullF16Range().map(f => {
- // Handles zeros, subnormals, and negatives
- if (f < 1.0) {
- return { input: f16(f), expected: u32(0) };
- }
-
- // All f16 no larger than <= 2^12 has a precise interger part and a fractional part, just need
- // to trunc towards 0 for the result integer.
- if (f <= 2 ** 12) {
- return { input: f16(f), expected: u32(Math.trunc(f)) };
- }
-
- // All f16s larger than 2 ** 12 are integers, so in theory one could use them directly, expect
- // that number is actually f64 internally, so they need to be quantized to f16 first.
- // Cannot just use trunc here, since that might produce a u32 value that is precise in f64,
- // but not in f16.
- return { input: f16(f), expected: u32(quantizeToF16(f)) };
- });
- },
-});
-
/** Generate a ShaderBuilder based on how the test case is to be vectorized */
function vectorizeToExpression(vectorize: undefined | 2 | 3 | 4): ShaderBuilder {
return vectorize === undefined ? unary('u32') : unary(`vec${vectorize}<u32>`);
@@ -117,7 +31,7 @@ The result is 1u if e is true and 0u otherwise
)
.fn(async t => {
const cases = await d.get('bool');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeBool], TypeU32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.bool], Type.u32, t.params, cases);
});
g.test('u32')
@@ -134,7 +48,7 @@ Identity operation
)
.fn(async t => {
const cases = await d.get('u32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeU32], TypeU32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.u32], Type.u32, t.params, cases);
});
g.test('i32')
@@ -151,7 +65,7 @@ Reinterpretation of bits
)
.fn(async t => {
const cases = await d.get('i32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeI32], TypeU32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.i32], Type.u32, t.params, cases);
});
g.test('f32')
@@ -168,7 +82,7 @@ e is converted to u32, rounding towards zero
)
.fn(async t => {
const cases = await d.get('f32');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeF32], TypeU32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.f32], Type.u32, t.params, cases);
});
g.test('f16')
@@ -188,7 +102,7 @@ e is converted to u32, rounding towards zero
})
.fn(async t => {
const cases = await d.get('f16');
- await run(t, vectorizeToExpression(t.params.vectorize), [TypeF16], TypeU32, t.params, cases);
+ await run(t, vectorizeToExpression(t.params.vectorize), [Type.f16], Type.u32, t.params, cases);
});
g.test('abstract_int')
@@ -201,6 +115,44 @@ Identity operation if the e can be represented in u32, otherwise it produces a s
`
)
.params(u =>
- u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const)
+ u
+ .combine('inputSource', onlyConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ )
+ .fn(async t => {
+ const cases = await d.get('abstractInt');
+ await run(
+ t,
+ vectorizeToExpression(t.params.vectorize),
+ [Type.abstractInt],
+ Type.u32,
+ t.params,
+ cases
+ );
+ });
+
+g.test('abstract_float')
+ .specURL('https://www.w3.org/TR/WGSL/#value-constructor-builtin-function')
+ .desc(
+ `
+u32(e), where e is an AbstractFloat
+
+e is converted to u32, rounding towards zero
+`
)
- .unimplemented();
+ .params(u =>
+ u
+ .combine('inputSource', onlyConstInputSource)
+ .combine('vectorize', [undefined, 2, 3, 4] as const)
+ )
+ .fn(async t => {
+ const cases = await d.get('abstractFloat');
+ await run(
+ t,
+ vectorizeToExpression(t.params.vectorize),
+ [Type.abstractFloat],
+ Type.u32,
+ t.params,
+ cases
+ );
+ });
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/unary.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/unary.ts
index 160e465178..109e6c1421 100644
--- a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/unary.ts
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/unary/unary.ts
@@ -1,5 +1,6 @@
import {
abstractFloatShaderBuilder,
+ abstractIntShaderBuilder,
basicExpressionBuilder,
ShaderBuilder,
} from '../expression.js';
@@ -10,6 +11,11 @@ export function unary(op: string): ShaderBuilder {
}
/* @returns a ShaderBuilder that evaluates a prefix unary operation that returns AbstractFloats */
-export function abstractUnary(op: string): ShaderBuilder {
+export function abstractFloatUnary(op: string): ShaderBuilder {
return abstractFloatShaderBuilder(value => `${op}(${value})`);
}
+
+/* @returns a ShaderBuilder that evaluates a prefix unary operation that returns AbstractInts */
+export function abstractIntUnary(op: string): ShaderBuilder {
+ return abstractIntShaderBuilder(value => `${op}(${value})`);
+}