diff --git a/docs/case_cache.md b/docs/case_cache.md
index 8e53834ce473..c3ba8718b5dd 100644
--- a/docs/case_cache.md
+++ b/docs/case_cache.md
@@ -9,8 +9,8 @@ for multiple CTS runs.
## File cache
To speed up execution of the CTS, the CTS git repo holds holds pre-computed
-test cases, serialized in a set of gzip-compressed binary files under
-[`src/resources/cache`](../src/resources/cache).
+test cases, generated from `*.cache.ts` files and serialized in a set of binary
+files under [`src/resources/cache`](../src/resources/cache).
These files are regenerated by [`src/common/tools/gen_cache.ts`](../src/common/tools/gen_cache.ts)
which can be run with `npx grunt run:generate-cache`.
@@ -24,10 +24,11 @@ output, and compares this hash to the hash stored in
[`src/resources/cache/hashes.json`](`../src/resources/cache/hashes.json`). Only
those cache files with differing hashes are rebuilt.
-Since source changes will sometimes change the hash without changing the generated cache,
-sometimes the cache will be regenerated unnecessarily. **This is OK, but try to avoid committing
-no-op regenerations - this will happen if your version of Node produces different gzip outputs
-than the original committer's Node did for the same input.**
+Transitive imports easily grow, and these can cause unnecessary rebuilds of the cache.
+To help avoid unnecessary rebuilds, files that are known to not be used by the cache can be
+annotated with a `MUST_NOT_BE_IMPORTED_BY_DATA_CACHE` comment anywhere in the file. If a file with
+this comment is transitively imported by a `.cache.ts` file, then the cache generation tool will
+error with a trace of the imports from the `.cache.ts` file to the file with this comment.
The cache files are copied from [`src/resources/cache`](../src/resources/cache)
to the `resources/cache` subdirectory of the
@@ -46,13 +47,15 @@ will build the cases during CTS execution and store the results in an in-memory
To add test cases to the cache:
-1. Import `makeCaseCache` from [`'case_cache.js'`](../src/webgpu/shader/execution/expression/case_cache.ts);
+1. Create a new my_file.cache.ts
file.
+
+2. In that file, import `makeCaseCache` from [`'case_cache.js'`](../src/webgpu/shader/execution/expression/case_cache.ts);
```ts
import { makeCaseCache } from '../case_cache.js'; // your relative path may vary
```
-2. Declare an exported global variable with the name `d`, assigned with the return value of `makeCaseCache()`:
+3. Declare an exported global variable with the name `d`, assigned with the return value of `makeCaseCache()`:
```ts
export const d = makeCaseCache('unique/path/of/your/cache/file', {
@@ -65,12 +68,14 @@ export const d = makeCaseCache('unique/path/of/your/cache/file', {
});
```
-3. To load the cases from the cache, use `d.get();`
+4. To use the cached cases in a my_file.spec.ts
file, import `d` from my_file.cache.js
, and use `d.get();`
```ts
+import { d } from './my_file.cache.js';
+
const cases = await d.get('name_of_your_case');
// cases will either be loaded from the cache file, loaded from the in-memory
// LRU, or built on the fly.
```
-4. Run `npx grunt run generate-cache` to generate the new cache file.
+5. Run `npx grunt run generate-cache` to generate the new cache file.
diff --git a/src/common/framework/data_cache.ts b/src/common/framework/data_cache.ts
index fea2bd203fae..c1e3a889beb3 100644
--- a/src/common/framework/data_cache.ts
+++ b/src/common/framework/data_cache.ts
@@ -187,11 +187,11 @@ export interface Cacheable {
/**
* serialize() encodes `data` to a binary representation so that it can be stored in a cache file.
*/
- serialize(data: Data): Promise;
+ serialize(data: Data): Uint8Array;
/**
* deserialize() is the inverse of serialize(), decoding the binary representation back to a Data
* object.
*/
- deserialize(binary: Uint8Array): Promise;
+ deserialize(binary: Uint8Array): Data;
}
diff --git a/src/common/tools/gen_cache.ts b/src/common/tools/gen_cache.ts
index 0ffbb373a0aa..d8309ebcb1c1 100644
--- a/src/common/tools/gen_cache.ts
+++ b/src/common/tools/gen_cache.ts
@@ -89,7 +89,7 @@ dataCache.setStore({
});
setIsBuildingDataCache();
-const specFileSuffix = __filename.endsWith('.ts') ? '.spec.ts' : '.spec.js';
+const cacheFileSuffix = __filename.endsWith('.ts') ? '.cache.ts' : '.cache.js';
/**
* @returns a list of all the files under 'dir' that has the given extension
@@ -105,6 +105,7 @@ function glob(dir: string, ext: string) {
files.push(`${file}/${child}`);
}
}
+
if (path.endsWith(ext) && fs.statSync(path).isFile()) {
files.push(file);
}
@@ -112,6 +113,19 @@ function glob(dir: string, ext: string) {
return files;
}
+/**
+ * Exception type thrown by SourceHasher.hashFile() when a file annotated with
+ * MUST_NOT_BE_IMPORTED_BY_DATA_CACHE is transitively imported by a .cache.ts file.
+ */
+class InvalidImportException {
+ constructor(path: string) {
+ this.stack = [path];
+ }
+ toString(): string {
+ return `invalid transitive import for cache:\n ${this.stack.join('\n ')}`;
+ }
+ readonly stack: string[];
+}
/**
* SourceHasher is a utility for producing a hash of a source .ts file and its imported source files.
*/
@@ -141,8 +155,19 @@ class SourceHasher {
const normalized = content.replace('\r\n', '\n');
let hash = crc32(normalized);
for (const importPath of parseImports(path, normalized)) {
- const importHash = this.hashFile(importPath);
- hash = this.hashCombine(hash, importHash);
+ try {
+ const importHash = this.hashFile(importPath);
+ hash = this.hashCombine(hash, importHash);
+ } catch (ex) {
+ if (ex instanceof InvalidImportException) {
+ ex.stack.push(path);
+ throw ex;
+ }
+ }
+ }
+
+ if (content.includes('MUST_NOT_BE_IMPORTED_BY_DATA_CACHE')) {
+ throw new InvalidImportException(path);
}
this.hashes.set(path, hash);
@@ -180,7 +205,7 @@ async function build(suiteDir: string) {
}
// Crawl files and convert paths to be POSIX-style, relative to suiteDir.
- const filesToEnumerate = glob(suiteDir, specFileSuffix)
+ const filesToEnumerate = glob(suiteDir, cacheFileSuffix)
.map(p => `${suiteDir}/${p}`)
.sort();
@@ -221,7 +246,7 @@ and
}
console.log(`building '${outPath}'`);
const data = await cacheable.build();
- const serialized = await cacheable.serialize(data);
+ const serialized = cacheable.serialize(data);
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, serialized, 'binary');
fileHashes[cacheable.path] = fileHash;
diff --git a/src/resources/cache/hashes.json b/src/resources/cache/hashes.json
index faf84a6bd0b9..171297b815c2 100644
--- a/src/resources/cache/hashes.json
+++ b/src/resources/cache/hashes.json
@@ -1,106 +1,106 @@
{
- "webgpu/shader/execution/binary/af_addition.bin": "8e47fc86",
- "webgpu/shader/execution/binary/af_logical.bin": "348bc279",
- "webgpu/shader/execution/binary/af_division.bin": "82029c55",
- "webgpu/shader/execution/binary/af_matrix_addition.bin": "6deae35e",
- "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "221a913c",
- "webgpu/shader/execution/binary/af_multiplication.bin": "53c87c5b",
- "webgpu/shader/execution/binary/af_remainder.bin": "dadb3ceb",
- "webgpu/shader/execution/binary/af_subtraction.bin": "a0a71e32",
- "webgpu/shader/execution/binary/f16_addition.bin": "acfee8",
- "webgpu/shader/execution/binary/f16_logical.bin": "78e0eec8",
- "webgpu/shader/execution/binary/f16_division.bin": "289b2aba",
- "webgpu/shader/execution/binary/f16_matrix_addition.bin": "bada3cbe",
- "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "bce23630",
- "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "2d6bcf91",
- "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "c3db5537",
- "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "402931c",
- "webgpu/shader/execution/binary/f16_multiplication.bin": "ce381066",
- "webgpu/shader/execution/binary/f16_remainder.bin": "b2bd9246",
- "webgpu/shader/execution/binary/f16_subtraction.bin": "7f7e9abc",
- "webgpu/shader/execution/binary/f32_addition.bin": "71302f1a",
- "webgpu/shader/execution/binary/f32_logical.bin": "ad34883d",
- "webgpu/shader/execution/binary/f32_division.bin": "b35602bb",
- "webgpu/shader/execution/binary/f32_matrix_addition.bin": "82339c4",
- "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "33c2bd83",
- "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "6b6dd016",
- "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "7733299f",
- "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "d99b4cc3",
- "webgpu/shader/execution/binary/f32_multiplication.bin": "ff22107c",
- "webgpu/shader/execution/binary/f32_remainder.bin": "44133c4c",
- "webgpu/shader/execution/binary/f32_subtraction.bin": "a9a5a319",
- "webgpu/shader/execution/binary/i32_arithmetic.bin": "eb21bd8f",
- "webgpu/shader/execution/binary/i32_comparison.bin": "83121ec4",
- "webgpu/shader/execution/binary/u32_arithmetic.bin": "8d1429d1",
- "webgpu/shader/execution/binary/u32_comparison.bin": "3491ba55",
- "webgpu/shader/execution/abs.bin": "a5dcabd0",
- "webgpu/shader/execution/acos.bin": "adbccc79",
- "webgpu/shader/execution/acosh.bin": "7c07ba41",
- "webgpu/shader/execution/asin.bin": "8fc62434",
- "webgpu/shader/execution/asinh.bin": "a00937c0",
- "webgpu/shader/execution/atan.bin": "a237eaa6",
- "webgpu/shader/execution/atan2.bin": "b41d74be",
- "webgpu/shader/execution/atanh.bin": "2b6934d5",
- "webgpu/shader/execution/bitcast.bin": "86e79d18",
- "webgpu/shader/execution/ceil.bin": "42a99291",
- "webgpu/shader/execution/clamp.bin": "b3fc754f",
- "webgpu/shader/execution/cos.bin": "13305519",
- "webgpu/shader/execution/cosh.bin": "20965093",
- "webgpu/shader/execution/cross.bin": "3cfeb2a1",
- "webgpu/shader/execution/degrees.bin": "6d9b3197",
- "webgpu/shader/execution/determinant.bin": "d09e35b7",
- "webgpu/shader/execution/distance.bin": "790d45ea",
- "webgpu/shader/execution/dot.bin": "5f7aa2bc",
- "webgpu/shader/execution/exp.bin": "932473",
- "webgpu/shader/execution/exp2.bin": "1ada59d6",
- "webgpu/shader/execution/faceForward.bin": "dc44d720",
- "webgpu/shader/execution/floor.bin": "cbbe2d21",
- "webgpu/shader/execution/fma.bin": "b5f22cac",
- "webgpu/shader/execution/fract.bin": "b9b72ee2",
- "webgpu/shader/execution/frexp.bin": "cc49a118",
- "webgpu/shader/execution/inverseSqrt.bin": "ab8d39ed",
- "webgpu/shader/execution/ldexp.bin": "cca23df2",
- "webgpu/shader/execution/length.bin": "4693ba28",
- "webgpu/shader/execution/log.bin": "75d7c534",
- "webgpu/shader/execution/log2.bin": "c0c65cb0",
- "webgpu/shader/execution/max.bin": "11d13c22",
- "webgpu/shader/execution/min.bin": "5c701467",
- "webgpu/shader/execution/mix.bin": "af998787",
- "webgpu/shader/execution/modf.bin": "3a3b367a",
- "webgpu/shader/execution/normalize.bin": "ce31e122",
- "webgpu/shader/execution/pack2x16float.bin": "d3198def",
- "webgpu/shader/execution/pow.bin": "847bf3ff",
- "webgpu/shader/execution/quantizeToF16.bin": "e2f5c3f9",
- "webgpu/shader/execution/radians.bin": "8869a385",
- "webgpu/shader/execution/reflect.bin": "2be62e10",
- "webgpu/shader/execution/refract.bin": "a95cf2a",
- "webgpu/shader/execution/round.bin": "cdc5ae01",
- "webgpu/shader/execution/saturate.bin": "bb20b07c",
- "webgpu/shader/execution/sign.bin": "a59f6a2b",
- "webgpu/shader/execution/sin.bin": "b36c7552",
- "webgpu/shader/execution/sinh.bin": "9385405",
- "webgpu/shader/execution/smoothstep.bin": "5d740ae7",
- "webgpu/shader/execution/sqrt.bin": "5e42a89b",
- "webgpu/shader/execution/step.bin": "4447b38c",
- "webgpu/shader/execution/tan.bin": "b47dfc33",
- "webgpu/shader/execution/tanh.bin": "8bd0ae74",
- "webgpu/shader/execution/transpose.bin": "afbbaef0",
- "webgpu/shader/execution/trunc.bin": "4d15f320",
- "webgpu/shader/execution/unpack2x16float.bin": "40ca16cc",
- "webgpu/shader/execution/unpack2x16snorm.bin": "39ece93e",
- "webgpu/shader/execution/unpack2x16unorm.bin": "dbdc06b8",
- "webgpu/shader/execution/unpack4x8snorm.bin": "c83bc6c2",
- "webgpu/shader/execution/unpack4x8unorm.bin": "678c5245",
- "webgpu/shader/execution/unary/af_arithmetic.bin": "1679466",
- "webgpu/shader/execution/unary/af_assignment.bin": "202b8019",
- "webgpu/shader/execution/unary/bool_conversion.bin": "6cb7e11a",
- "webgpu/shader/execution/unary/f16_arithmetic.bin": "d0409431",
- "webgpu/shader/execution/unary/f16_conversion.bin": "884688a",
- "webgpu/shader/execution/unary/f32_arithmetic.bin": "8925bac7",
- "webgpu/shader/execution/unary/f32_conversion.bin": "798aaba2",
- "webgpu/shader/execution/unary/i32_arithmetic.bin": "c21ece3",
- "webgpu/shader/execution/unary/i32_complement.bin": "f65f0bec",
- "webgpu/shader/execution/unary/i32_conversion.bin": "7ce468a1",
- "webgpu/shader/execution/unary/u32_complement.bin": "d6408865",
- "webgpu/shader/execution/unary/u32_conversion.bin": "aa09fe0"
+ "webgpu/shader/execution/binary/af_addition.bin": "b5345cca",
+ "webgpu/shader/execution/binary/af_logical.bin": "9ec85311",
+ "webgpu/shader/execution/binary/af_division.bin": "23dd840e",
+ "webgpu/shader/execution/binary/af_matrix_addition.bin": "ee95539e",
+ "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "a2e64d57",
+ "webgpu/shader/execution/binary/af_multiplication.bin": "94d7a574",
+ "webgpu/shader/execution/binary/af_remainder.bin": "79f5abc4",
+ "webgpu/shader/execution/binary/af_subtraction.bin": "62dce5bf",
+ "webgpu/shader/execution/binary/f16_addition.bin": "ab3b4d9c",
+ "webgpu/shader/execution/binary/f16_logical.bin": "1edd08ec",
+ "webgpu/shader/execution/binary/f16_division.bin": "849eed26",
+ "webgpu/shader/execution/binary/f16_matrix_addition.bin": "54afc3f8",
+ "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "df5d3ccc",
+ "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "3be6032e",
+ "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "98a29837",
+ "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "c463d7e0",
+ "webgpu/shader/execution/binary/f16_multiplication.bin": "cdf0775d",
+ "webgpu/shader/execution/binary/f16_remainder.bin": "e82ef89f",
+ "webgpu/shader/execution/binary/f16_subtraction.bin": "5125b5b0",
+ "webgpu/shader/execution/binary/f32_addition.bin": "d3b8004",
+ "webgpu/shader/execution/binary/f32_logical.bin": "fab7cfc5",
+ "webgpu/shader/execution/binary/f32_division.bin": "e9fdb0a9",
+ "webgpu/shader/execution/binary/f32_matrix_addition.bin": "d1165469",
+ "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "45a79521",
+ "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "bf8da7d0",
+ "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "82d7fa9",
+ "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "57eebe84",
+ "webgpu/shader/execution/binary/f32_multiplication.bin": "eb0baa56",
+ "webgpu/shader/execution/binary/f32_remainder.bin": "e6059990",
+ "webgpu/shader/execution/binary/f32_subtraction.bin": "d57cfa1",
+ "webgpu/shader/execution/binary/i32_arithmetic.bin": "de93ee2a",
+ "webgpu/shader/execution/binary/i32_comparison.bin": "aaa1f21b",
+ "webgpu/shader/execution/binary/u32_arithmetic.bin": "d79a1011",
+ "webgpu/shader/execution/binary/u32_comparison.bin": "31764c75",
+ "webgpu/shader/execution/abs.bin": "9278901c",
+ "webgpu/shader/execution/acos.bin": "9c77ebf9",
+ "webgpu/shader/execution/acosh.bin": "2baaf7cc",
+ "webgpu/shader/execution/asin.bin": "8fd7a678",
+ "webgpu/shader/execution/asinh.bin": "321a7294",
+ "webgpu/shader/execution/atan.bin": "d3dada7e",
+ "webgpu/shader/execution/atan2.bin": "2871596c",
+ "webgpu/shader/execution/atanh.bin": "e7158ef",
+ "webgpu/shader/execution/bitcast.bin": "aa7d6f0e",
+ "webgpu/shader/execution/ceil.bin": "3c1d91ad",
+ "webgpu/shader/execution/clamp.bin": "a53fdbda",
+ "webgpu/shader/execution/cos.bin": "73b83288",
+ "webgpu/shader/execution/cosh.bin": "39ca32a4",
+ "webgpu/shader/execution/cross.bin": "409c3e26",
+ "webgpu/shader/execution/degrees.bin": "a44bb2b1",
+ "webgpu/shader/execution/determinant.bin": "41a06528",
+ "webgpu/shader/execution/distance.bin": "fe3ea84f",
+ "webgpu/shader/execution/dot.bin": "f70abfec",
+ "webgpu/shader/execution/exp.bin": "7587e11b",
+ "webgpu/shader/execution/exp2.bin": "c6f34d2b",
+ "webgpu/shader/execution/faceForward.bin": "8eb57a7d",
+ "webgpu/shader/execution/floor.bin": "b9ea647b",
+ "webgpu/shader/execution/fma.bin": "b9f657b2",
+ "webgpu/shader/execution/fract.bin": "73a18e4f",
+ "webgpu/shader/execution/frexp.bin": "857fe9b7",
+ "webgpu/shader/execution/inverseSqrt.bin": "a595983a",
+ "webgpu/shader/execution/ldexp.bin": "a04aaeca",
+ "webgpu/shader/execution/length.bin": "695740fb",
+ "webgpu/shader/execution/log.bin": "6703ec1a",
+ "webgpu/shader/execution/log2.bin": "8339559d",
+ "webgpu/shader/execution/max.bin": "ec000a56",
+ "webgpu/shader/execution/min.bin": "156cf7cc",
+ "webgpu/shader/execution/mix.bin": "32064d21",
+ "webgpu/shader/execution/modf.bin": "a5003ce0",
+ "webgpu/shader/execution/normalize.bin": "c12bac96",
+ "webgpu/shader/execution/pack2x16float.bin": "b2cb12ea",
+ "webgpu/shader/execution/pow.bin": "ee87eccb",
+ "webgpu/shader/execution/quantizeToF16.bin": "f77ae7e3",
+ "webgpu/shader/execution/radians.bin": "7ecbe5be",
+ "webgpu/shader/execution/reflect.bin": "d37034bd",
+ "webgpu/shader/execution/refract.bin": "6dc9adcf",
+ "webgpu/shader/execution/round.bin": "d91faa0f",
+ "webgpu/shader/execution/saturate.bin": "93230980",
+ "webgpu/shader/execution/sign.bin": "fb1071b8",
+ "webgpu/shader/execution/sin.bin": "a9ed8361",
+ "webgpu/shader/execution/sinh.bin": "65ba80fc",
+ "webgpu/shader/execution/smoothstep.bin": "17e1e103",
+ "webgpu/shader/execution/sqrt.bin": "4c29a5d4",
+ "webgpu/shader/execution/step.bin": "aed08458",
+ "webgpu/shader/execution/tan.bin": "5f671594",
+ "webgpu/shader/execution/tanh.bin": "991e903a",
+ "webgpu/shader/execution/transpose.bin": "9d388797",
+ "webgpu/shader/execution/trunc.bin": "959fe8bc",
+ "webgpu/shader/execution/unpack2x16float.bin": "26e5b05e",
+ "webgpu/shader/execution/unpack2x16snorm.bin": "c756d8a3",
+ "webgpu/shader/execution/unpack2x16unorm.bin": "5257591a",
+ "webgpu/shader/execution/unpack4x8snorm.bin": "83fbd41a",
+ "webgpu/shader/execution/unpack4x8unorm.bin": "77d46acb",
+ "webgpu/shader/execution/unary/af_arithmetic.bin": "2edb2dc5",
+ "webgpu/shader/execution/unary/af_assignment.bin": "36c04bba",
+ "webgpu/shader/execution/unary/bool_conversion.bin": "cb53bf65",
+ "webgpu/shader/execution/unary/f16_arithmetic.bin": "9f459fc4",
+ "webgpu/shader/execution/unary/f16_conversion.bin": "bf055ca9",
+ "webgpu/shader/execution/unary/f32_arithmetic.bin": "e15c49e7",
+ "webgpu/shader/execution/unary/f32_conversion.bin": "92e5069f",
+ "webgpu/shader/execution/unary/i32_arithmetic.bin": "d322b73d",
+ "webgpu/shader/execution/unary/i32_complement.bin": "c4e6cbb",
+ "webgpu/shader/execution/unary/i32_conversion.bin": "d6905a0f",
+ "webgpu/shader/execution/unary/u32_complement.bin": "d0e4aa97",
+ "webgpu/shader/execution/unary/u32_conversion.bin": "5a96b263"
}
\ No newline at end of file
diff --git a/src/resources/cache/webgpu/shader/execution/abs.bin b/src/resources/cache/webgpu/shader/execution/abs.bin
index 6223beff8744..16111ac66a32 100644
Binary files a/src/resources/cache/webgpu/shader/execution/abs.bin and b/src/resources/cache/webgpu/shader/execution/abs.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/acos.bin b/src/resources/cache/webgpu/shader/execution/acos.bin
index 1977729e5c60..3765fcd2bef8 100644
Binary files a/src/resources/cache/webgpu/shader/execution/acos.bin and b/src/resources/cache/webgpu/shader/execution/acos.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/acosh.bin b/src/resources/cache/webgpu/shader/execution/acosh.bin
index 4f725dcaf127..ee127796edb4 100644
Binary files a/src/resources/cache/webgpu/shader/execution/acosh.bin and b/src/resources/cache/webgpu/shader/execution/acosh.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/asin.bin b/src/resources/cache/webgpu/shader/execution/asin.bin
index ad64140d1e7f..439de48fb3f1 100644
Binary files a/src/resources/cache/webgpu/shader/execution/asin.bin and b/src/resources/cache/webgpu/shader/execution/asin.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/asinh.bin b/src/resources/cache/webgpu/shader/execution/asinh.bin
index 45ad2368d194..eda7179e7597 100644
Binary files a/src/resources/cache/webgpu/shader/execution/asinh.bin and b/src/resources/cache/webgpu/shader/execution/asinh.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/atan.bin b/src/resources/cache/webgpu/shader/execution/atan.bin
index f36c10fd9f6c..d15ee8b6b7f2 100644
Binary files a/src/resources/cache/webgpu/shader/execution/atan.bin and b/src/resources/cache/webgpu/shader/execution/atan.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/atan2.bin b/src/resources/cache/webgpu/shader/execution/atan2.bin
index 723303abdfb5..2966b4ea155c 100644
Binary files a/src/resources/cache/webgpu/shader/execution/atan2.bin and b/src/resources/cache/webgpu/shader/execution/atan2.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/atanh.bin b/src/resources/cache/webgpu/shader/execution/atanh.bin
index 471fec788360..d919b4bcb782 100644
Binary files a/src/resources/cache/webgpu/shader/execution/atanh.bin and b/src/resources/cache/webgpu/shader/execution/atanh.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_addition.bin b/src/resources/cache/webgpu/shader/execution/binary/af_addition.bin
index 349208085f7f..ebd757c1b6b1 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_addition.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_addition.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_division.bin b/src/resources/cache/webgpu/shader/execution/binary/af_division.bin
index e40a7de36c5f..af690dcfb53f 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_division.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_division.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_logical.bin b/src/resources/cache/webgpu/shader/execution/binary/af_logical.bin
index 4ef63b4a7e77..e386de36b7e8 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_logical.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_logical.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_addition.bin b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_addition.bin
index a64f636c3808..d387abcd7f20 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_addition.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_addition.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_subtraction.bin b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_subtraction.bin
index ca0574b737e9..4a1449182109 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_subtraction.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_subtraction.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/af_multiplication.bin
index 2c8ab384831e..552d8b4892c8 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_multiplication.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_remainder.bin b/src/resources/cache/webgpu/shader/execution/binary/af_remainder.bin
index a9b404623e38..b9cd253ac7ca 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_remainder.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_remainder.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_subtraction.bin b/src/resources/cache/webgpu/shader/execution/binary/af_subtraction.bin
index e38720094465..6f0be2978587 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_subtraction.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_subtraction.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_addition.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_addition.bin
index efc7d2aeed51..30f099139dd4 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_addition.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_addition.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_division.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_division.bin
index fe0bae88cc4a..c05b627fa121 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_division.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_division.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_logical.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_logical.bin
index f9449065b6c0..558a25ded450 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_logical.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_logical.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_addition.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_addition.bin
index 71834238de53..452376760bd3 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_addition.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_addition.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin
index 09b86396c9da..6d5f4e1ea1fd 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin
index e29b38f5f486..b48be81ebd2a 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_subtraction.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_subtraction.bin
index 591a12e3c067..386558c3f768 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_subtraction.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_subtraction.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin
index 0b6fa6f8aa8d..cbf224a6b638 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_multiplication.bin
index d304084d0972..e9d27019a3b4 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_multiplication.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_remainder.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_remainder.bin
index 870492b379a4..d21370aec98c 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_remainder.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_remainder.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f16_subtraction.bin b/src/resources/cache/webgpu/shader/execution/binary/f16_subtraction.bin
index b3d83ab375ce..97080a8ce547 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f16_subtraction.bin and b/src/resources/cache/webgpu/shader/execution/binary/f16_subtraction.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_addition.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_addition.bin
index ccc443387641..be7b997bd8eb 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_addition.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_addition.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_division.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_division.bin
index cad4b6d5ca82..f80461c21b48 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_division.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_division.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_logical.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_logical.bin
index d9b5e494a046..5a6fbe92d5d2 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_logical.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_logical.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_addition.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_addition.bin
index e0ca837fffde..b1d7179264c6 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_addition.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_addition.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin
index 5cee2264ebfe..9c36c9e8b5c2 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin
index b6d84399d89a..76f867b959ec 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_subtraction.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_subtraction.bin
index 2faffe9327db..0d0fd2460d72 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_subtraction.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_subtraction.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin
index 9ca7f6bbddc0..e139fc971300 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_multiplication.bin
index 43ef17cdf19b..1837ce922c56 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_multiplication.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_remainder.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_remainder.bin
index 477bf6cc3fa5..3febfca1d1cb 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_remainder.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_remainder.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/f32_subtraction.bin b/src/resources/cache/webgpu/shader/execution/binary/f32_subtraction.bin
index db5975e48288..32b34f690cc6 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/f32_subtraction.bin and b/src/resources/cache/webgpu/shader/execution/binary/f32_subtraction.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/i32_arithmetic.bin b/src/resources/cache/webgpu/shader/execution/binary/i32_arithmetic.bin
index a2fcd52c5bd2..55880fdeeded 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/i32_arithmetic.bin and b/src/resources/cache/webgpu/shader/execution/binary/i32_arithmetic.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/i32_comparison.bin b/src/resources/cache/webgpu/shader/execution/binary/i32_comparison.bin
index 2acf5c4e7f97..4bc8882dea92 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/i32_comparison.bin and b/src/resources/cache/webgpu/shader/execution/binary/i32_comparison.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/u32_arithmetic.bin b/src/resources/cache/webgpu/shader/execution/binary/u32_arithmetic.bin
index a016e61d5eec..56ef2928645a 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/u32_arithmetic.bin and b/src/resources/cache/webgpu/shader/execution/binary/u32_arithmetic.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/binary/u32_comparison.bin b/src/resources/cache/webgpu/shader/execution/binary/u32_comparison.bin
index 28c0ca1b9552..5ba639b3cdad 100644
Binary files a/src/resources/cache/webgpu/shader/execution/binary/u32_comparison.bin and b/src/resources/cache/webgpu/shader/execution/binary/u32_comparison.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/bitcast.bin b/src/resources/cache/webgpu/shader/execution/bitcast.bin
index 0eb0dcf77736..808ddd88bd19 100644
Binary files a/src/resources/cache/webgpu/shader/execution/bitcast.bin and b/src/resources/cache/webgpu/shader/execution/bitcast.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/ceil.bin b/src/resources/cache/webgpu/shader/execution/ceil.bin
index 5a726de3168a..5ec60b6e150d 100644
Binary files a/src/resources/cache/webgpu/shader/execution/ceil.bin and b/src/resources/cache/webgpu/shader/execution/ceil.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/clamp.bin b/src/resources/cache/webgpu/shader/execution/clamp.bin
index aef9dc89c97c..1ceb3f19a10d 100644
Binary files a/src/resources/cache/webgpu/shader/execution/clamp.bin and b/src/resources/cache/webgpu/shader/execution/clamp.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/cos.bin b/src/resources/cache/webgpu/shader/execution/cos.bin
index a90a7b369eb1..a7951b447025 100644
Binary files a/src/resources/cache/webgpu/shader/execution/cos.bin and b/src/resources/cache/webgpu/shader/execution/cos.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/cosh.bin b/src/resources/cache/webgpu/shader/execution/cosh.bin
index 08c7ebafdeee..693b2d3230e7 100644
Binary files a/src/resources/cache/webgpu/shader/execution/cosh.bin and b/src/resources/cache/webgpu/shader/execution/cosh.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/cross.bin b/src/resources/cache/webgpu/shader/execution/cross.bin
index 0a2ee02fa153..64041c731193 100644
Binary files a/src/resources/cache/webgpu/shader/execution/cross.bin and b/src/resources/cache/webgpu/shader/execution/cross.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/degrees.bin b/src/resources/cache/webgpu/shader/execution/degrees.bin
index fc44af06f59b..715e6b656f74 100644
Binary files a/src/resources/cache/webgpu/shader/execution/degrees.bin and b/src/resources/cache/webgpu/shader/execution/degrees.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/determinant.bin b/src/resources/cache/webgpu/shader/execution/determinant.bin
index b7518c304ffd..cef09cd67bd1 100644
Binary files a/src/resources/cache/webgpu/shader/execution/determinant.bin and b/src/resources/cache/webgpu/shader/execution/determinant.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/distance.bin b/src/resources/cache/webgpu/shader/execution/distance.bin
index 27ece1a02778..68e892671e1f 100644
Binary files a/src/resources/cache/webgpu/shader/execution/distance.bin and b/src/resources/cache/webgpu/shader/execution/distance.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/dot.bin b/src/resources/cache/webgpu/shader/execution/dot.bin
index 7a6977a83a24..9c243ea4f004 100644
Binary files a/src/resources/cache/webgpu/shader/execution/dot.bin and b/src/resources/cache/webgpu/shader/execution/dot.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/exp.bin b/src/resources/cache/webgpu/shader/execution/exp.bin
index 9b92a23ea968..0c4ed5bfea0a 100644
Binary files a/src/resources/cache/webgpu/shader/execution/exp.bin and b/src/resources/cache/webgpu/shader/execution/exp.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/exp2.bin b/src/resources/cache/webgpu/shader/execution/exp2.bin
index 0ca78a214eb2..7ffbb062f1b2 100644
Binary files a/src/resources/cache/webgpu/shader/execution/exp2.bin and b/src/resources/cache/webgpu/shader/execution/exp2.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/faceForward.bin b/src/resources/cache/webgpu/shader/execution/faceForward.bin
index d3bca445284d..13436dde01b1 100644
Binary files a/src/resources/cache/webgpu/shader/execution/faceForward.bin and b/src/resources/cache/webgpu/shader/execution/faceForward.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/floor.bin b/src/resources/cache/webgpu/shader/execution/floor.bin
index fc9ca8cf331d..a4b363825bea 100644
Binary files a/src/resources/cache/webgpu/shader/execution/floor.bin and b/src/resources/cache/webgpu/shader/execution/floor.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/fma.bin b/src/resources/cache/webgpu/shader/execution/fma.bin
index 751d8f75703e..db54353a5262 100644
Binary files a/src/resources/cache/webgpu/shader/execution/fma.bin and b/src/resources/cache/webgpu/shader/execution/fma.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/fract.bin b/src/resources/cache/webgpu/shader/execution/fract.bin
index aa11d27b2885..566b95144f3c 100644
Binary files a/src/resources/cache/webgpu/shader/execution/fract.bin and b/src/resources/cache/webgpu/shader/execution/fract.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/frexp.bin b/src/resources/cache/webgpu/shader/execution/frexp.bin
index 5b534b1520df..2e20d4ce033d 100644
Binary files a/src/resources/cache/webgpu/shader/execution/frexp.bin and b/src/resources/cache/webgpu/shader/execution/frexp.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/inverseSqrt.bin b/src/resources/cache/webgpu/shader/execution/inverseSqrt.bin
index cbfa62107600..731c62903cc2 100644
Binary files a/src/resources/cache/webgpu/shader/execution/inverseSqrt.bin and b/src/resources/cache/webgpu/shader/execution/inverseSqrt.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/ldexp.bin b/src/resources/cache/webgpu/shader/execution/ldexp.bin
index 4c94aa669a7e..d441928d1cb7 100644
Binary files a/src/resources/cache/webgpu/shader/execution/ldexp.bin and b/src/resources/cache/webgpu/shader/execution/ldexp.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/length.bin b/src/resources/cache/webgpu/shader/execution/length.bin
index c9ef2fe9b5de..9ecedd7d997f 100644
Binary files a/src/resources/cache/webgpu/shader/execution/length.bin and b/src/resources/cache/webgpu/shader/execution/length.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/log.bin b/src/resources/cache/webgpu/shader/execution/log.bin
index 981182412d3b..5c860bfaa65c 100644
Binary files a/src/resources/cache/webgpu/shader/execution/log.bin and b/src/resources/cache/webgpu/shader/execution/log.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/log2.bin b/src/resources/cache/webgpu/shader/execution/log2.bin
index 1d7563a88fbf..7f6d35346b33 100644
Binary files a/src/resources/cache/webgpu/shader/execution/log2.bin and b/src/resources/cache/webgpu/shader/execution/log2.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/max.bin b/src/resources/cache/webgpu/shader/execution/max.bin
index 3330d3e34112..63704eb23300 100644
Binary files a/src/resources/cache/webgpu/shader/execution/max.bin and b/src/resources/cache/webgpu/shader/execution/max.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/min.bin b/src/resources/cache/webgpu/shader/execution/min.bin
index f90e78691eb8..18b26a3bf8c8 100644
Binary files a/src/resources/cache/webgpu/shader/execution/min.bin and b/src/resources/cache/webgpu/shader/execution/min.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/mix.bin b/src/resources/cache/webgpu/shader/execution/mix.bin
index faaf0df313eb..4cf9083aed69 100644
Binary files a/src/resources/cache/webgpu/shader/execution/mix.bin and b/src/resources/cache/webgpu/shader/execution/mix.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/modf.bin b/src/resources/cache/webgpu/shader/execution/modf.bin
index fa1483bc7aa0..e5387db46257 100644
Binary files a/src/resources/cache/webgpu/shader/execution/modf.bin and b/src/resources/cache/webgpu/shader/execution/modf.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/normalize.bin b/src/resources/cache/webgpu/shader/execution/normalize.bin
index 524639326060..434bbe2dd167 100644
Binary files a/src/resources/cache/webgpu/shader/execution/normalize.bin and b/src/resources/cache/webgpu/shader/execution/normalize.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/pack2x16float.bin b/src/resources/cache/webgpu/shader/execution/pack2x16float.bin
index db6b5f242a53..e95227d36e50 100644
Binary files a/src/resources/cache/webgpu/shader/execution/pack2x16float.bin and b/src/resources/cache/webgpu/shader/execution/pack2x16float.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/pow.bin b/src/resources/cache/webgpu/shader/execution/pow.bin
index 688f18cad37b..1f23a1f3818a 100644
Binary files a/src/resources/cache/webgpu/shader/execution/pow.bin and b/src/resources/cache/webgpu/shader/execution/pow.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/quantizeToF16.bin b/src/resources/cache/webgpu/shader/execution/quantizeToF16.bin
index b18ec2b667e9..9e4308d5cd30 100644
Binary files a/src/resources/cache/webgpu/shader/execution/quantizeToF16.bin and b/src/resources/cache/webgpu/shader/execution/quantizeToF16.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/radians.bin b/src/resources/cache/webgpu/shader/execution/radians.bin
index bdf713d1b2bc..63c7cc3ccd5b 100644
Binary files a/src/resources/cache/webgpu/shader/execution/radians.bin and b/src/resources/cache/webgpu/shader/execution/radians.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/reflect.bin b/src/resources/cache/webgpu/shader/execution/reflect.bin
index c4f066e11332..6608646fd01e 100644
Binary files a/src/resources/cache/webgpu/shader/execution/reflect.bin and b/src/resources/cache/webgpu/shader/execution/reflect.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/refract.bin b/src/resources/cache/webgpu/shader/execution/refract.bin
index ec22e1d6a728..934e44e644bc 100644
Binary files a/src/resources/cache/webgpu/shader/execution/refract.bin and b/src/resources/cache/webgpu/shader/execution/refract.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/round.bin b/src/resources/cache/webgpu/shader/execution/round.bin
index cdbdfef8e259..c3b30b68f0a1 100644
Binary files a/src/resources/cache/webgpu/shader/execution/round.bin and b/src/resources/cache/webgpu/shader/execution/round.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/saturate.bin b/src/resources/cache/webgpu/shader/execution/saturate.bin
index 676d4878a6f6..39df7169b750 100644
Binary files a/src/resources/cache/webgpu/shader/execution/saturate.bin and b/src/resources/cache/webgpu/shader/execution/saturate.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/sign.bin b/src/resources/cache/webgpu/shader/execution/sign.bin
index cddd0c88bac0..2f3b2aa258b2 100644
Binary files a/src/resources/cache/webgpu/shader/execution/sign.bin and b/src/resources/cache/webgpu/shader/execution/sign.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/sin.bin b/src/resources/cache/webgpu/shader/execution/sin.bin
index 0b3a32bd67dc..d583876c518c 100644
Binary files a/src/resources/cache/webgpu/shader/execution/sin.bin and b/src/resources/cache/webgpu/shader/execution/sin.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/sinh.bin b/src/resources/cache/webgpu/shader/execution/sinh.bin
index 9cd9463a1de9..072c53393f46 100644
Binary files a/src/resources/cache/webgpu/shader/execution/sinh.bin and b/src/resources/cache/webgpu/shader/execution/sinh.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/smoothstep.bin b/src/resources/cache/webgpu/shader/execution/smoothstep.bin
index 07a8cff9159a..43aac2b1c46d 100644
Binary files a/src/resources/cache/webgpu/shader/execution/smoothstep.bin and b/src/resources/cache/webgpu/shader/execution/smoothstep.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/sqrt.bin b/src/resources/cache/webgpu/shader/execution/sqrt.bin
index 8068f869a6b3..f466d2379f65 100644
Binary files a/src/resources/cache/webgpu/shader/execution/sqrt.bin and b/src/resources/cache/webgpu/shader/execution/sqrt.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/step.bin b/src/resources/cache/webgpu/shader/execution/step.bin
index 4bd371f9d8e6..03f251cb65cf 100644
Binary files a/src/resources/cache/webgpu/shader/execution/step.bin and b/src/resources/cache/webgpu/shader/execution/step.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/tan.bin b/src/resources/cache/webgpu/shader/execution/tan.bin
index 21ce4e7cb44f..aafb900347d0 100644
Binary files a/src/resources/cache/webgpu/shader/execution/tan.bin and b/src/resources/cache/webgpu/shader/execution/tan.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/tanh.bin b/src/resources/cache/webgpu/shader/execution/tanh.bin
index aa15a9409fab..709427217c26 100644
Binary files a/src/resources/cache/webgpu/shader/execution/tanh.bin and b/src/resources/cache/webgpu/shader/execution/tanh.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/transpose.bin b/src/resources/cache/webgpu/shader/execution/transpose.bin
index 58acdd9e802d..d1b6bf04ee7e 100644
Binary files a/src/resources/cache/webgpu/shader/execution/transpose.bin and b/src/resources/cache/webgpu/shader/execution/transpose.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/trunc.bin b/src/resources/cache/webgpu/shader/execution/trunc.bin
index 065e118daeba..ba81e2ada427 100644
Binary files a/src/resources/cache/webgpu/shader/execution/trunc.bin and b/src/resources/cache/webgpu/shader/execution/trunc.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/af_arithmetic.bin b/src/resources/cache/webgpu/shader/execution/unary/af_arithmetic.bin
index 8d79aa10e475..21d3d702ae9f 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/af_arithmetic.bin and b/src/resources/cache/webgpu/shader/execution/unary/af_arithmetic.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/af_assignment.bin b/src/resources/cache/webgpu/shader/execution/unary/af_assignment.bin
index 852066cf67a6..a92279b5ce4e 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/af_assignment.bin and b/src/resources/cache/webgpu/shader/execution/unary/af_assignment.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/bool_conversion.bin b/src/resources/cache/webgpu/shader/execution/unary/bool_conversion.bin
index 5b4d9ebdcaea..98a90ea45b9a 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/bool_conversion.bin and b/src/resources/cache/webgpu/shader/execution/unary/bool_conversion.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/f16_arithmetic.bin b/src/resources/cache/webgpu/shader/execution/unary/f16_arithmetic.bin
index 989a623f40c7..acf8a702cee1 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/f16_arithmetic.bin and b/src/resources/cache/webgpu/shader/execution/unary/f16_arithmetic.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/f16_conversion.bin b/src/resources/cache/webgpu/shader/execution/unary/f16_conversion.bin
index 764769fc6217..5b386b070434 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/f16_conversion.bin and b/src/resources/cache/webgpu/shader/execution/unary/f16_conversion.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/f32_arithmetic.bin b/src/resources/cache/webgpu/shader/execution/unary/f32_arithmetic.bin
index 83c566986107..ebc60029fa60 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/f32_arithmetic.bin and b/src/resources/cache/webgpu/shader/execution/unary/f32_arithmetic.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/f32_conversion.bin b/src/resources/cache/webgpu/shader/execution/unary/f32_conversion.bin
index c71bc25a3ada..bdcc0c72988e 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/f32_conversion.bin and b/src/resources/cache/webgpu/shader/execution/unary/f32_conversion.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/i32_arithmetic.bin b/src/resources/cache/webgpu/shader/execution/unary/i32_arithmetic.bin
index c3a962cb3646..4753b020c965 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/i32_arithmetic.bin and b/src/resources/cache/webgpu/shader/execution/unary/i32_arithmetic.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/i32_complement.bin b/src/resources/cache/webgpu/shader/execution/unary/i32_complement.bin
index 24eff7d07681..f7b8bd680c37 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/i32_complement.bin and b/src/resources/cache/webgpu/shader/execution/unary/i32_complement.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/i32_conversion.bin b/src/resources/cache/webgpu/shader/execution/unary/i32_conversion.bin
index 9f6e54ce3586..74c5d000e3f6 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/i32_conversion.bin and b/src/resources/cache/webgpu/shader/execution/unary/i32_conversion.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/u32_complement.bin b/src/resources/cache/webgpu/shader/execution/unary/u32_complement.bin
index 5978b45b590f..526456273e48 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/u32_complement.bin and b/src/resources/cache/webgpu/shader/execution/unary/u32_complement.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unary/u32_conversion.bin b/src/resources/cache/webgpu/shader/execution/unary/u32_conversion.bin
index bda5494e1355..609caf94fe68 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unary/u32_conversion.bin and b/src/resources/cache/webgpu/shader/execution/unary/u32_conversion.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unpack2x16float.bin b/src/resources/cache/webgpu/shader/execution/unpack2x16float.bin
index e3eec4572642..7f06cb0df6b3 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unpack2x16float.bin and b/src/resources/cache/webgpu/shader/execution/unpack2x16float.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unpack2x16snorm.bin b/src/resources/cache/webgpu/shader/execution/unpack2x16snorm.bin
index acd39ca05b9d..08c6af9e9398 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unpack2x16snorm.bin and b/src/resources/cache/webgpu/shader/execution/unpack2x16snorm.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unpack2x16unorm.bin b/src/resources/cache/webgpu/shader/execution/unpack2x16unorm.bin
index 90c62a32a19a..1bb97b9c556a 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unpack2x16unorm.bin and b/src/resources/cache/webgpu/shader/execution/unpack2x16unorm.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unpack4x8snorm.bin b/src/resources/cache/webgpu/shader/execution/unpack4x8snorm.bin
index 04fb255842dd..1db9856b0562 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unpack4x8snorm.bin and b/src/resources/cache/webgpu/shader/execution/unpack4x8snorm.bin differ
diff --git a/src/resources/cache/webgpu/shader/execution/unpack4x8unorm.bin b/src/resources/cache/webgpu/shader/execution/unpack4x8unorm.bin
index 30c4a0c0ddc3..8d1f3dc7fb8f 100644
Binary files a/src/resources/cache/webgpu/shader/execution/unpack4x8unorm.bin and b/src/resources/cache/webgpu/shader/execution/unpack4x8unorm.bin differ
diff --git a/src/webgpu/shader/execution/expression/binary/af_addition.cache.ts b/src/webgpu/shader/execution/expression/binary/af_addition.cache.ts
new file mode 100644
index 000000000000..f5e9d3b481a5
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/af_addition.cache.ts
@@ -0,0 +1,54 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF64Range, sparseVectorF64Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const additionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.abstract.toVector(v.map(e => FP.abstract.additionInterval(e, s)));
+};
+
+const additionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.abstract.toVector(v.map(e => FP.abstract.additionInterval(s, e)));
+};
+
+const scalar_cases = {
+ ['scalar']: () => {
+ return FP.abstract.generateScalarPairToIntervalCases(
+ sparseScalarF64Range(),
+ sparseScalarF64Range(),
+ 'finite',
+ FP.abstract.additionInterval
+ );
+ },
+};
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .map(dim => ({
+ [`vec${dim}_scalar`]: () => {
+ return FP.abstract.generateVectorScalarToVectorCases(
+ sparseVectorF64Range(dim),
+ sparseScalarF64Range(),
+ 'finite',
+ additionVectorScalarInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .map(dim => ({
+ [`scalar_vec${dim}`]: () => {
+ return FP.abstract.generateScalarVectorToVectorCases(
+ sparseScalarF64Range(),
+ sparseVectorF64Range(dim),
+ 'finite',
+ additionScalarVectorInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/af_addition', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/af_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/af_addition.spec.ts
index 29fb42e386b0..b34fb4f150dd 100644
--- a/src/webgpu/shader/execution/expression/binary/af_addition.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/af_addition.spec.ts
@@ -5,66 +5,13 @@ Execution Tests for non-matrix AbstractFloat addition expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeAbstractFloat, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF64Range, sparseVectorF64Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { onlyConstInputSource, run } from '../expression.js';
+import { d } from './af_addition.cache.js';
import { abstractBinary } from './binary.js';
-const additionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.abstract.toVector(v.map(e => FP.abstract.additionInterval(e, s)));
-};
-
-const additionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.abstract.toVector(v.map(e => FP.abstract.additionInterval(s, e)));
-};
-
export const g = makeTestGroup(GPUTest);
-const scalar_cases = {
- ['scalar']: () => {
- return FP.abstract.generateScalarPairToIntervalCases(
- sparseScalarF64Range(),
- sparseScalarF64Range(),
- 'finite',
- FP.abstract.additionInterval
- );
- },
-};
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .map(dim => ({
- [`vec${dim}_scalar`]: () => {
- return FP.abstract.generateVectorScalarToVectorCases(
- sparseVectorF64Range(dim),
- sparseScalarF64Range(),
- 'finite',
- additionVectorScalarInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .map(dim => ({
- [`scalar_vec${dim}`]: () => {
- return FP.abstract.generateScalarVectorToVectorCases(
- sparseScalarF64Range(),
- sparseVectorF64Range(dim),
- 'finite',
- additionScalarVectorInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/af_addition', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/af_comparison.cache.ts b/src/webgpu/shader/execution/expression/binary/af_comparison.cache.ts
new file mode 100644
index 000000000000..648ea5c0b0b8
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/af_comparison.cache.ts
@@ -0,0 +1,90 @@
+import { anyOf } from '../../../../util/compare.js';
+import { abstractFloat, bool, Scalar } from '../../../../util/conversion.js';
+import { flushSubnormalNumberF64, vectorF64Range } from '../../../../util/math.js';
+import { Case } from '../case.js';
+import { makeCaseCache } from '../case_cache.js';
+
+/**
+ * @returns a test case for the provided left hand & right hand values and truth function.
+ * Handles quantization and subnormals.
+ */
+function makeCase(
+ lhs: number,
+ rhs: number,
+ truthFunc: (lhs: Scalar, rhs: Scalar) => boolean
+): Case {
+ // Subnormal float values may be flushed at any time.
+ // https://www.w3.org/TR/WGSL/#floating-point-evaluation
+ const af_lhs = abstractFloat(lhs);
+ const af_rhs = abstractFloat(rhs);
+ const lhs_options = new Set([af_lhs, abstractFloat(flushSubnormalNumberF64(lhs))]);
+ const rhs_options = new Set([af_rhs, abstractFloat(flushSubnormalNumberF64(rhs))]);
+ const expected: Array = [];
+ lhs_options.forEach(l => {
+ rhs_options.forEach(r => {
+ const result = bool(truthFunc(l, r));
+ if (!expected.includes(result)) {
+ expected.push(result);
+ }
+ });
+ });
+
+ return { input: [af_lhs, af_rhs], expected: anyOf(...expected) };
+}
+
+export const d = makeCaseCache('binary/af_logical', {
+ equals: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) === (rhs.value as number);
+ };
+
+ return vectorF64Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ not_equals: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) !== (rhs.value as number);
+ };
+
+ return vectorF64Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ less_than: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) < (rhs.value as number);
+ };
+
+ return vectorF64Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ less_equals: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) <= (rhs.value as number);
+ };
+
+ return vectorF64Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ greater_than: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) > (rhs.value as number);
+ };
+
+ return vectorF64Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ greater_equals: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) >= (rhs.value as number);
+ };
+
+ return vectorF64Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/binary/af_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/af_comparison.spec.ts
index 5b8b1637b9db..cc03ee4367f2 100644
--- a/src/webgpu/shader/execution/expression/binary/af_comparison.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/af_comparison.spec.ts
@@ -4,107 +4,14 @@ Execution Tests for the AbstractFloat comparison operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { anyOf } from '../../../../util/compare.js';
-import {
- abstractFloat,
- bool,
- Scalar,
- TypeAbstractFloat,
- TypeBool,
-} from '../../../../util/conversion.js';
-import { flushSubnormalNumberF64, vectorF64Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, Case, run } from '../expression.js';
+import { TypeAbstractFloat, TypeBool } from '../../../../util/conversion.js';
+import { allInputSources, run } from '../expression.js';
+import { d } from './af_comparison.cache.js';
import { binary } from './binary.js';
export const g = makeTestGroup(GPUTest);
-/**
- * @returns a test case for the provided left hand & right hand values and truth function.
- * Handles quantization and subnormals.
- */
-function makeCase(
- lhs: number,
- rhs: number,
- truthFunc: (lhs: Scalar, rhs: Scalar) => boolean
-): Case {
- // Subnormal float values may be flushed at any time.
- // https://www.w3.org/TR/WGSL/#floating-point-evaluation
- const af_lhs = abstractFloat(lhs);
- const af_rhs = abstractFloat(rhs);
- const lhs_options = new Set([af_lhs, abstractFloat(flushSubnormalNumberF64(lhs))]);
- const rhs_options = new Set([af_rhs, abstractFloat(flushSubnormalNumberF64(rhs))]);
- const expected: Array = [];
- lhs_options.forEach(l => {
- rhs_options.forEach(r => {
- const result = bool(truthFunc(l, r));
- if (!expected.includes(result)) {
- expected.push(result);
- }
- });
- });
-
- return { input: [af_lhs, af_rhs], expected: anyOf(...expected) };
-}
-
-export const d = makeCaseCache('binary/af_logical', {
- equals: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) === (rhs.value as number);
- };
-
- return vectorF64Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- not_equals: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) !== (rhs.value as number);
- };
-
- return vectorF64Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- less_than: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) < (rhs.value as number);
- };
-
- return vectorF64Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- less_equals: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) <= (rhs.value as number);
- };
-
- return vectorF64Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- greater_than: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) > (rhs.value as number);
- };
-
- return vectorF64Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- greater_equals: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) >= (rhs.value as number);
- };
-
- return vectorF64Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
-});
-
g.test('equals')
.specURL('https://www.w3.org/TR/WGSL/#comparison-expr')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/af_division.cache.ts b/src/webgpu/shader/execution/expression/binary/af_division.cache.ts
new file mode 100644
index 000000000000..5af293b3de28
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/af_division.cache.ts
@@ -0,0 +1,54 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF64Range, sparseVectorF64Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const divisionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.abstract.toVector(v.map(e => FP.abstract.divisionInterval(e, s)));
+};
+
+const divisionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.abstract.toVector(v.map(e => FP.abstract.divisionInterval(s, e)));
+};
+
+const scalar_cases = {
+ ['scalar']: () => {
+ return FP.abstract.generateScalarPairToIntervalCases(
+ sparseScalarF64Range(),
+ sparseScalarF64Range(),
+ 'finite',
+ FP.abstract.divisionInterval
+ );
+ },
+};
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .map(dim => ({
+ [`vec${dim}_scalar`]: () => {
+ return FP.abstract.generateVectorScalarToVectorCases(
+ sparseVectorF64Range(dim),
+ sparseScalarF64Range(),
+ 'finite',
+ divisionVectorScalarInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .map(dim => ({
+ [`scalar_vec${dim}`]: () => {
+ return FP.abstract.generateScalarVectorToVectorCases(
+ sparseScalarF64Range(),
+ sparseVectorF64Range(dim),
+ 'finite',
+ divisionScalarVectorInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/af_division', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/af_division.spec.ts b/src/webgpu/shader/execution/expression/binary/af_division.spec.ts
index 6b2cd819f4ee..1e5492a34d9c 100644
--- a/src/webgpu/shader/execution/expression/binary/af_division.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/af_division.spec.ts
@@ -5,66 +5,13 @@ Execution Tests for non-matrix AbstractFloat division expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeAbstractFloat, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF64Range, sparseVectorF64Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { onlyConstInputSource, run } from '../expression.js';
+import { d } from './af_division.cache.js';
import { abstractBinary } from './binary.js';
-const divisionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.abstract.toVector(v.map(e => FP.abstract.divisionInterval(e, s)));
-};
-
-const divisionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.abstract.toVector(v.map(e => FP.abstract.divisionInterval(s, e)));
-};
-
export const g = makeTestGroup(GPUTest);
-const scalar_cases = {
- ['scalar']: () => {
- return FP.abstract.generateScalarPairToIntervalCases(
- sparseScalarF64Range(),
- sparseScalarF64Range(),
- 'finite',
- FP.abstract.divisionInterval
- );
- },
-};
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .map(dim => ({
- [`vec${dim}_scalar`]: () => {
- return FP.abstract.generateVectorScalarToVectorCases(
- sparseVectorF64Range(dim),
- sparseScalarF64Range(),
- 'finite',
- divisionVectorScalarInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .map(dim => ({
- [`scalar_vec${dim}`]: () => {
- return FP.abstract.generateScalarVectorToVectorCases(
- sparseScalarF64Range(),
- sparseVectorF64Range(dim),
- 'finite',
- divisionScalarVectorInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/af_division', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_addition.cache.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_addition.cache.ts
new file mode 100644
index 000000000000..75c13d7702b6
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/af_matrix_addition.cache.ts
@@ -0,0 +1,21 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF64Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matCxR
+const mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).map(rows => ({
+ [`mat${cols}x${rows}`]: () => {
+ return FP.abstract.generateMatrixPairToMatrixCases(
+ sparseMatrixF64Range(cols, rows),
+ sparseMatrixF64Range(cols, rows),
+ 'finite',
+ FP.abstract.additionMatrixMatrixInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/af_matrix_addition', mat_cases);
diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_addition.spec.ts
index 86bddec89467..9f232c1ef6e6 100644
--- a/src/webgpu/shader/execution/expression/binary/af_matrix_addition.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/af_matrix_addition.spec.ts
@@ -5,33 +5,13 @@ Execution Tests for matrix AbstractFloat addition expressions
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeAbstractFloat, TypeMat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseMatrixF64Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { onlyConstInputSource, run } from '../expression.js';
+import { d } from './af_matrix_addition.cache.js';
import { abstractBinary } from './binary.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matCxR
-const mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).map(rows => ({
- [`mat${cols}x${rows}`]: () => {
- return FP.abstract.generateMatrixPairToMatrixCases(
- sparseMatrixF64Range(cols, rows),
- sparseMatrixF64Range(cols, rows),
- 'finite',
- FP.abstract.additionMatrixMatrixInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/af_matrix_addition', mat_cases);
-
g.test('matrix')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.cache.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.cache.ts
new file mode 100644
index 000000000000..b030f369e3d3
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.cache.ts
@@ -0,0 +1,21 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF64Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matCxR
+const mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).map(rows => ({
+ [`mat${cols}x${rows}`]: () => {
+ return FP.abstract.generateMatrixPairToMatrixCases(
+ sparseMatrixF64Range(cols, rows),
+ sparseMatrixF64Range(cols, rows),
+ 'finite',
+ FP.abstract.subtractionMatrixMatrixInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/af_matrix_subtraction', mat_cases);
diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.spec.ts
index 849c11611f80..2697d1fe8cb0 100644
--- a/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.spec.ts
@@ -5,33 +5,13 @@ Execution Tests for matrix AbstractFloat subtraction expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeAbstractFloat, TypeMat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseMatrixF64Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { onlyConstInputSource, run } from '../expression.js';
+import { d } from './af_matrix_subtraction.cache.js';
import { abstractBinary } from './binary.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matCxR
-const mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).map(rows => ({
- [`mat${cols}x${rows}`]: () => {
- return FP.abstract.generateMatrixPairToMatrixCases(
- sparseMatrixF64Range(cols, rows),
- sparseMatrixF64Range(cols, rows),
- 'finite',
- FP.abstract.subtractionMatrixMatrixInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/af_matrix_subtraction', mat_cases);
-
g.test('matrix')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/af_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/af_multiplication.cache.ts
new file mode 100644
index 000000000000..e111682cd28a
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/af_multiplication.cache.ts
@@ -0,0 +1,54 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF64Range, sparseVectorF64Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const multiplicationVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.abstract.toVector(v.map(e => FP.abstract.multiplicationInterval(e, s)));
+};
+
+const multiplicationScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.abstract.toVector(v.map(e => FP.abstract.multiplicationInterval(s, e)));
+};
+
+const scalar_cases = {
+ ['scalar']: () => {
+ return FP.abstract.generateScalarPairToIntervalCases(
+ sparseScalarF64Range(),
+ sparseScalarF64Range(),
+ 'finite',
+ FP.abstract.multiplicationInterval
+ );
+ },
+};
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .map(dim => ({
+ [`vec${dim}_scalar`]: () => {
+ return FP.abstract.generateVectorScalarToVectorCases(
+ sparseVectorF64Range(dim),
+ sparseScalarF64Range(),
+ 'finite',
+ multiplicationVectorScalarInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .map(dim => ({
+ [`scalar_vec${dim}`]: () => {
+ return FP.abstract.generateScalarVectorToVectorCases(
+ sparseScalarF64Range(),
+ sparseVectorF64Range(dim),
+ 'finite',
+ multiplicationScalarVectorInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/af_multiplication', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/af_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/af_multiplication.spec.ts
index 61626203b8b7..57beaca49ee8 100644
--- a/src/webgpu/shader/execution/expression/binary/af_multiplication.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/af_multiplication.spec.ts
@@ -5,66 +5,13 @@ Execution Tests for non-matrix AbstractFloat multiplication expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeAbstractFloat, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF64Range, sparseVectorF64Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { onlyConstInputSource, run } from '../expression.js';
+import { d } from './af_multiplication.cache.js';
import { abstractBinary } from './binary.js';
-const multiplicationVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.abstract.toVector(v.map(e => FP.abstract.multiplicationInterval(e, s)));
-};
-
-const multiplicationScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.abstract.toVector(v.map(e => FP.abstract.multiplicationInterval(s, e)));
-};
-
export const g = makeTestGroup(GPUTest);
-const scalar_cases = {
- ['scalar']: () => {
- return FP.abstract.generateScalarPairToIntervalCases(
- sparseScalarF64Range(),
- sparseScalarF64Range(),
- 'finite',
- FP.abstract.multiplicationInterval
- );
- },
-};
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .map(dim => ({
- [`vec${dim}_scalar`]: () => {
- return FP.abstract.generateVectorScalarToVectorCases(
- sparseVectorF64Range(dim),
- sparseScalarF64Range(),
- 'finite',
- multiplicationVectorScalarInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .map(dim => ({
- [`scalar_vec${dim}`]: () => {
- return FP.abstract.generateScalarVectorToVectorCases(
- sparseScalarF64Range(),
- sparseVectorF64Range(dim),
- 'finite',
- multiplicationScalarVectorInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/af_multiplication', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/af_remainder.cache.ts b/src/webgpu/shader/execution/expression/binary/af_remainder.cache.ts
new file mode 100644
index 000000000000..eba0a27760b0
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/af_remainder.cache.ts
@@ -0,0 +1,54 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF64Range, sparseVectorF64Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const remainderVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.abstract.toVector(v.map(e => FP.abstract.remainderInterval(e, s)));
+};
+
+const remainderScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.abstract.toVector(v.map(e => FP.abstract.remainderInterval(s, e)));
+};
+
+const scalar_cases = {
+ ['scalar']: () => {
+ return FP.abstract.generateScalarPairToIntervalCases(
+ sparseScalarF64Range(),
+ sparseScalarF64Range(),
+ 'finite',
+ FP.abstract.remainderInterval
+ );
+ },
+};
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .map(dim => ({
+ [`vec${dim}_scalar`]: () => {
+ return FP.abstract.generateVectorScalarToVectorCases(
+ sparseVectorF64Range(dim),
+ sparseScalarF64Range(),
+ 'finite',
+ remainderVectorScalarInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .map(dim => ({
+ [`scalar_vec${dim}`]: () => {
+ return FP.abstract.generateScalarVectorToVectorCases(
+ sparseScalarF64Range(),
+ sparseVectorF64Range(dim),
+ 'finite',
+ remainderScalarVectorInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/af_remainder', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/af_remainder.spec.ts b/src/webgpu/shader/execution/expression/binary/af_remainder.spec.ts
index 12002e867747..f53cb781b7cb 100644
--- a/src/webgpu/shader/execution/expression/binary/af_remainder.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/af_remainder.spec.ts
@@ -5,66 +5,13 @@ Execution Tests for non-matrix abstract float remainder expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeAbstractFloat, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF64Range, sparseVectorF64Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { onlyConstInputSource, run } from '../expression.js';
+import { d } from './af_remainder.cache.js';
import { abstractBinary } from './binary.js';
-const remainderVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.abstract.toVector(v.map(e => FP.abstract.remainderInterval(e, s)));
-};
-
-const remainderScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.abstract.toVector(v.map(e => FP.abstract.remainderInterval(s, e)));
-};
-
export const g = makeTestGroup(GPUTest);
-const scalar_cases = {
- ['scalar']: () => {
- return FP.abstract.generateScalarPairToIntervalCases(
- sparseScalarF64Range(),
- sparseScalarF64Range(),
- 'finite',
- FP.abstract.remainderInterval
- );
- },
-};
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .map(dim => ({
- [`vec${dim}_scalar`]: () => {
- return FP.abstract.generateVectorScalarToVectorCases(
- sparseVectorF64Range(dim),
- sparseScalarF64Range(),
- 'finite',
- remainderVectorScalarInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .map(dim => ({
- [`scalar_vec${dim}`]: () => {
- return FP.abstract.generateScalarVectorToVectorCases(
- sparseScalarF64Range(),
- sparseVectorF64Range(dim),
- 'finite',
- remainderScalarVectorInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/af_remainder', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/af_subtraction.cache.ts b/src/webgpu/shader/execution/expression/binary/af_subtraction.cache.ts
new file mode 100644
index 000000000000..ea5107e143fc
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/af_subtraction.cache.ts
@@ -0,0 +1,54 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF64Range, sparseVectorF64Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const subtractionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.abstract.toVector(v.map(e => FP.abstract.subtractionInterval(e, s)));
+};
+
+const subtractionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.abstract.toVector(v.map(e => FP.abstract.subtractionInterval(s, e)));
+};
+
+const scalar_cases = {
+ ['scalar']: () => {
+ return FP.abstract.generateScalarPairToIntervalCases(
+ sparseScalarF64Range(),
+ sparseScalarF64Range(),
+ 'finite',
+ FP.abstract.subtractionInterval
+ );
+ },
+};
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .map(dim => ({
+ [`vec${dim}_scalar`]: () => {
+ return FP.abstract.generateVectorScalarToVectorCases(
+ sparseVectorF64Range(dim),
+ sparseScalarF64Range(),
+ 'finite',
+ subtractionVectorScalarInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .map(dim => ({
+ [`scalar_vec${dim}`]: () => {
+ return FP.abstract.generateScalarVectorToVectorCases(
+ sparseScalarF64Range(),
+ sparseVectorF64Range(dim),
+ 'finite',
+ subtractionScalarVectorInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/af_subtraction', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/af_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/af_subtraction.spec.ts
index 09617a6379a8..b9e304fa134f 100644
--- a/src/webgpu/shader/execution/expression/binary/af_subtraction.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/af_subtraction.spec.ts
@@ -5,66 +5,13 @@ Execution Tests for non-matrix AbstractFloat subtraction expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeAbstractFloat, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF64Range, sparseVectorF64Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { onlyConstInputSource, run } from '../expression.js';
+import { d } from './af_subtraction.cache.js';
import { abstractBinary } from './binary.js';
-const subtractionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.abstract.toVector(v.map(e => FP.abstract.subtractionInterval(e, s)));
-};
-
-const subtractionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.abstract.toVector(v.map(e => FP.abstract.subtractionInterval(s, e)));
-};
-
export const g = makeTestGroup(GPUTest);
-const scalar_cases = {
- ['scalar']: () => {
- return FP.abstract.generateScalarPairToIntervalCases(
- sparseScalarF64Range(),
- sparseScalarF64Range(),
- 'finite',
- FP.abstract.subtractionInterval
- );
- },
-};
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .map(dim => ({
- [`vec${dim}_scalar`]: () => {
- return FP.abstract.generateVectorScalarToVectorCases(
- sparseVectorF64Range(dim),
- sparseScalarF64Range(),
- 'finite',
- subtractionVectorScalarInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .map(dim => ({
- [`scalar_vec${dim}`]: () => {
- return FP.abstract.generateScalarVectorToVectorCases(
- sparseScalarF64Range(),
- sparseVectorF64Range(dim),
- 'finite',
- subtractionScalarVectorInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/af_subtraction', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/bitwise_shift.spec.ts b/src/webgpu/shader/execution/expression/binary/bitwise_shift.spec.ts
index 5457b7ceab54..b47d66a47964 100644
--- a/src/webgpu/shader/execution/expression/binary/bitwise_shift.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/bitwise_shift.spec.ts
@@ -5,7 +5,8 @@ Execution Tests for the bitwise shift binary expression operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { i32, scalarType, ScalarType, TypeU32, u32 } from '../../../../util/conversion.js';
-import { allInputSources, CaseList, run } from '../expression.js';
+import { CaseList } from '../case.js';
+import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
diff --git a/src/webgpu/shader/execution/expression/binary/f16_addition.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_addition.cache.ts
new file mode 100644
index 000000000000..f179d48a131b
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_addition.cache.ts
@@ -0,0 +1,60 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF16Range, sparseVectorF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const additionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.f16.toVector(v.map(e => FP.f16.additionInterval(e, s)));
+};
+
+const additionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.f16.toVector(v.map(e => FP.f16.additionInterval(s, e)));
+};
+
+const scalar_cases = ([true, false] as const)
+ .map(nonConst => ({
+ [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarPairToIntervalCases(
+ sparseScalarF16Range(),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.additionInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateVectorScalarToVectorCases(
+ sparseVectorF16Range(dim),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ additionVectorScalarInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarVectorToVectorCases(
+ sparseScalarF16Range(),
+ sparseVectorF16Range(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ additionScalarVectorInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f16_addition', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f16_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_addition.spec.ts
index 99c08db43681..7f94c7e307a9 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_addition.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_addition.spec.ts
@@ -5,72 +5,13 @@ Execution Tests for non-matrix f16 addition expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF16, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF16Range, sparseVectorF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-const additionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.f16.toVector(v.map(e => FP.f16.additionInterval(e, s)));
-};
-
-const additionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.f16.toVector(v.map(e => FP.f16.additionInterval(s, e)));
-};
+import { d } from './f16_addition.cache.js';
export const g = makeTestGroup(GPUTest);
-const scalar_cases = ([true, false] as const)
- .map(nonConst => ({
- [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarPairToIntervalCases(
- sparseScalarF16Range(),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.additionInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateVectorScalarToVectorCases(
- sparseVectorF16Range(dim),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- additionVectorScalarInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarVectorToVectorCases(
- sparseScalarF16Range(),
- sparseVectorF16Range(dim),
- nonConst ? 'unfiltered' : 'finite',
- additionScalarVectorInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f16_addition', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f16_comparison.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_comparison.cache.ts
new file mode 100644
index 000000000000..92d926a412b9
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_comparison.cache.ts
@@ -0,0 +1,144 @@
+import { anyOf } from '../../../../util/compare.js';
+import { bool, f16, Scalar } from '../../../../util/conversion.js';
+import { flushSubnormalNumberF16, vectorF16Range } from '../../../../util/math.js';
+import { Case } from '../case.js';
+import { makeCaseCache } from '../case_cache.js';
+
+/**
+ * @returns a test case for the provided left hand & right hand values and truth function.
+ * Handles quantization and subnormals.
+ */
+function makeCase(
+ lhs: number,
+ rhs: number,
+ truthFunc: (lhs: Scalar, rhs: Scalar) => boolean
+): Case {
+ // Subnormal float values may be flushed at any time.
+ // https://www.w3.org/TR/WGSL/#floating-point-evaluation
+ const f16_lhs = f16(lhs);
+ const f16_rhs = f16(rhs);
+ const lhs_options = new Set([f16_lhs, f16(flushSubnormalNumberF16(lhs))]);
+ const rhs_options = new Set([f16_rhs, f16(flushSubnormalNumberF16(rhs))]);
+ const expected: Array = [];
+ lhs_options.forEach(l => {
+ rhs_options.forEach(r => {
+ const result = bool(truthFunc(l, r));
+ if (!expected.includes(result)) {
+ expected.push(result);
+ }
+ });
+ });
+
+ return { input: [f16_lhs, f16_rhs], expected: anyOf(...expected) };
+}
+
+export const d = makeCaseCache('binary/f16_logical', {
+ equals_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) === (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ equals_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) === (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ not_equals_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) !== (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ not_equals_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) !== (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ less_than_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) < (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ less_than_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) < (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ less_equals_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) <= (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ less_equals_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) <= (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ greater_than_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) > (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ greater_than_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) > (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ greater_equals_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) >= (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ greater_equals_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) >= (rhs.value as number);
+ };
+
+ return vectorF16Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f16_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_comparison.spec.ts
index ae7e1675c5ac..c84080983de5 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_comparison.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_comparison.spec.ts
@@ -4,155 +4,14 @@ Execution Tests for the f16 comparison operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { anyOf } from '../../../../util/compare.js';
-import { bool, f16, Scalar, TypeBool, TypeF16 } from '../../../../util/conversion.js';
-import { flushSubnormalNumberF16, vectorF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, Case, run } from '../expression.js';
+import { TypeBool, TypeF16 } from '../../../../util/conversion.js';
+import { allInputSources, run } from '../expression.js';
import { binary } from './binary.js';
+import { d } from './f16_comparison.cache.js';
export const g = makeTestGroup(GPUTest);
-/**
- * @returns a test case for the provided left hand & right hand values and truth function.
- * Handles quantization and subnormals.
- */
-function makeCase(
- lhs: number,
- rhs: number,
- truthFunc: (lhs: Scalar, rhs: Scalar) => boolean
-): Case {
- // Subnormal float values may be flushed at any time.
- // https://www.w3.org/TR/WGSL/#floating-point-evaluation
- const f16_lhs = f16(lhs);
- const f16_rhs = f16(rhs);
- const lhs_options = new Set([f16_lhs, f16(flushSubnormalNumberF16(lhs))]);
- const rhs_options = new Set([f16_rhs, f16(flushSubnormalNumberF16(rhs))]);
- const expected: Array = [];
- lhs_options.forEach(l => {
- rhs_options.forEach(r => {
- const result = bool(truthFunc(l, r));
- if (!expected.includes(result)) {
- expected.push(result);
- }
- });
- });
-
- return { input: [f16_lhs, f16_rhs], expected: anyOf(...expected) };
-}
-
-export const d = makeCaseCache('binary/f16_logical', {
- equals_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) === (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- equals_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) === (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- not_equals_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) !== (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- not_equals_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) !== (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- less_than_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) < (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- less_than_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) < (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- less_equals_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) <= (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- less_equals_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) <= (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- greater_than_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) > (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- greater_than_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) > (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- greater_equals_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) >= (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- greater_equals_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) >= (rhs.value as number);
- };
-
- return vectorF16Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
-});
-
g.test('equals')
.specURL('https://www.w3.org/TR/WGSL/#comparison-expr')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f16_division.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_division.cache.ts
new file mode 100644
index 000000000000..95590ca46789
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_division.cache.ts
@@ -0,0 +1,60 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF16Range, sparseVectorF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const divisionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.f16.toVector(v.map(e => FP.f16.divisionInterval(e, s)));
+};
+
+const divisionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.f16.toVector(v.map(e => FP.f16.divisionInterval(s, e)));
+};
+
+const scalar_cases = ([true, false] as const)
+ .map(nonConst => ({
+ [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarPairToIntervalCases(
+ sparseScalarF16Range(),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.divisionInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateVectorScalarToVectorCases(
+ sparseVectorF16Range(dim),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ divisionVectorScalarInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarVectorToVectorCases(
+ sparseScalarF16Range(),
+ sparseVectorF16Range(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ divisionScalarVectorInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f16_division', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f16_division.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_division.spec.ts
index 725c90828071..7dfc13f81a2f 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_division.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_division.spec.ts
@@ -5,72 +5,13 @@ Execution Tests for non-matrix f16 division expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF16, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF16Range, sparseVectorF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-const divisionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.f16.toVector(v.map(e => FP.f16.divisionInterval(e, s)));
-};
-
-const divisionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.f16.toVector(v.map(e => FP.f16.divisionInterval(s, e)));
-};
+import { d } from './f16_division.cache.js';
export const g = makeTestGroup(GPUTest);
-const scalar_cases = ([true, false] as const)
- .map(nonConst => ({
- [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarPairToIntervalCases(
- sparseScalarF16Range(),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.divisionInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateVectorScalarToVectorCases(
- sparseVectorF16Range(dim),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- divisionVectorScalarInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarVectorToVectorCases(
- sparseScalarF16Range(),
- sparseVectorF16Range(dim),
- nonConst ? 'unfiltered' : 'finite',
- divisionScalarVectorInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f16_division', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.cache.ts
new file mode 100644
index 000000000000..a670b08b0740
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.cache.ts
@@ -0,0 +1,23 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matCxR_[non_]const
+const mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateMatrixPairToMatrixCases(
+ sparseMatrixF16Range(cols, rows),
+ sparseMatrixF16Range(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.additionMatrixMatrixInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f16_matrix_addition', mat_cases);
diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.spec.ts
index fe64f41503fd..daf768a5365c 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.spec.ts
@@ -5,35 +5,13 @@ Execution Tests for matrix f16 addition expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF16, TypeMat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseMatrixF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
+import { d } from './f16_matrix_addition.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matCxR_[non_]const
-const mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateMatrixPairToMatrixCases(
- sparseMatrixF16Range(cols, rows),
- sparseMatrixF16Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.additionMatrixMatrixInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f16_matrix_addition', mat_cases);
-
g.test('matrix')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.cache.ts
new file mode 100644
index 000000000000..a31813abb3ba
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.cache.ts
@@ -0,0 +1,25 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matKxR_matCxK_[non_]const
+const mat_mat_cases = ([2, 3, 4] as const)
+ .flatMap(k =>
+ ([2, 3, 4] as const).flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`mat${k}x${rows}_mat${cols}x${k}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateMatrixPairToMatrixCases(
+ sparseMatrixF16Range(k, rows),
+ sparseMatrixF16Range(cols, k),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.multiplicationMatrixMatrixInterval
+ );
+ },
+ }))
+ )
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f16_matrix_matrix_multiplication', mat_mat_cases);
diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.spec.ts
index 0c8b3e8c51c4..69c56c60c368 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.spec.ts
@@ -5,37 +5,13 @@ Execution Tests for matrix-matrix f16 multiplication expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF16, TypeMat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseMatrixF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
+import { d } from './f16_matrix_matrix_multiplication.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matKxR_matCxK_[non_]const
-const mat_mat_cases = ([2, 3, 4] as const)
- .flatMap(k =>
- ([2, 3, 4] as const).flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`mat${k}x${rows}_mat${cols}x${k}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateMatrixPairToMatrixCases(
- sparseMatrixF16Range(k, rows),
- sparseMatrixF16Range(cols, k),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.multiplicationMatrixMatrixInterval
- );
- },
- }))
- )
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f16_matrix_matrix_multiplication', mat_mat_cases);
-
g.test('matrix_matrix')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.cache.ts
new file mode 100644
index 000000000000..f902a1c8bc8d
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.cache.ts
@@ -0,0 +1,44 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF16Range, sparseScalarF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matCxR_scalar_[non_]const
+const mat_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`mat${cols}x${rows}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateMatrixScalarToMatrixCases(
+ sparseMatrixF16Range(cols, rows),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.multiplicationMatrixScalarInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: scalar_matCxR_[non_]const
+const scalar_mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarMatrixToMatrixCases(
+ sparseScalarF16Range(),
+ sparseMatrixF16Range(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.multiplicationScalarMatrixInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f16_matrix_scalar_multiplication', {
+ ...mat_scalar_cases,
+ ...scalar_mat_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.spec.ts
index 83f583f9b6d7..338d6d021bb5 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.spec.ts
@@ -5,56 +5,13 @@ Execution Tests for matrix-scalar and scalar-matrix f16 multiplication expressio
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF16, TypeMat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseScalarF16Range, sparseMatrixF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
+import { d } from './f16_matrix_scalar_multiplication.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matCxR_scalar_[non_]const
-const mat_scalar_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`mat${cols}x${rows}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateMatrixScalarToMatrixCases(
- sparseMatrixF16Range(cols, rows),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.multiplicationMatrixScalarInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: scalar_matCxR_[non_]const
-const scalar_mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarMatrixToMatrixCases(
- sparseScalarF16Range(),
- sparseMatrixF16Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.multiplicationScalarMatrixInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f16_matrix_scalar_multiplication', {
- ...mat_scalar_cases,
- ...scalar_mat_cases,
-});
-
g.test('matrix_scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.cache.ts
new file mode 100644
index 000000000000..a6edcf7fe500
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.cache.ts
@@ -0,0 +1,23 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matCxR_[non_]const
+const mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateMatrixPairToMatrixCases(
+ sparseMatrixF16Range(cols, rows),
+ sparseMatrixF16Range(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.subtractionMatrixMatrixInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f16_matrix_subtraction', mat_cases);
diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.spec.ts
index 5b5f6ba04e3f..442c31ef82e9 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.spec.ts
@@ -5,35 +5,13 @@ Execution Tests for matrix f16 subtraction expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF16, TypeMat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseMatrixF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
+import { d } from './f16_matrix_subtraction.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matCxR_[non_]const
-const mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateMatrixPairToMatrixCases(
- sparseMatrixF16Range(cols, rows),
- sparseMatrixF16Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.subtractionMatrixMatrixInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f16_matrix_subtraction', mat_cases);
-
g.test('matrix')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.cache.ts
new file mode 100644
index 000000000000..7b822386feb2
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.cache.ts
@@ -0,0 +1,44 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF16Range, sparseVectorF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matCxR_vecC_[non_]const
+const mat_vec_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`mat${cols}x${rows}_vec${cols}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateMatrixVectorToVectorCases(
+ sparseMatrixF16Range(cols, rows),
+ sparseVectorF16Range(cols),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.multiplicationMatrixVectorInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: vecR_matCxR_[non_]const
+const vec_mat_cases = ([2, 3, 4] as const)
+ .flatMap(rows =>
+ ([2, 3, 4] as const).flatMap(cols =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${rows}_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateVectorMatrixToVectorCases(
+ sparseVectorF16Range(rows),
+ sparseMatrixF16Range(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.multiplicationVectorMatrixInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f16_matrix_vector_multiplication', {
+ ...mat_vec_cases,
+ ...vec_mat_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.spec.ts
index 3e916c7fd400..9715fe681e35 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.spec.ts
@@ -5,56 +5,13 @@ Execution Tests for matrix-vector and vector-matrix f16 multiplication expressio
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF16, TypeMat, TypeVec } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseMatrixF16Range, sparseVectorF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
+import { d } from './f16_matrix_vector_multiplication.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matCxR_vecC_[non_]const
-const mat_vec_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`mat${cols}x${rows}_vec${cols}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateMatrixVectorToVectorCases(
- sparseMatrixF16Range(cols, rows),
- sparseVectorF16Range(cols),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.multiplicationMatrixVectorInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: vecR_matCxR_[non_]const
-const vec_mat_cases = ([2, 3, 4] as const)
- .flatMap(rows =>
- ([2, 3, 4] as const).flatMap(cols =>
- ([true, false] as const).map(nonConst => ({
- [`vec${rows}_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateVectorMatrixToVectorCases(
- sparseVectorF16Range(rows),
- sparseMatrixF16Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.multiplicationVectorMatrixInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f16_matrix_vector_multiplication', {
- ...mat_vec_cases,
- ...vec_mat_cases,
-});
-
g.test('matrix_vector')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f16_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_multiplication.cache.ts
new file mode 100644
index 000000000000..a94f55ccf0e5
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_multiplication.cache.ts
@@ -0,0 +1,60 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF16Range, sparseVectorF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const multiplicationVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.f16.toVector(v.map(e => FP.f16.multiplicationInterval(e, s)));
+};
+
+const multiplicationScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.f16.toVector(v.map(e => FP.f16.multiplicationInterval(s, e)));
+};
+
+const scalar_cases = ([true, false] as const)
+ .map(nonConst => ({
+ [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarPairToIntervalCases(
+ sparseScalarF16Range(),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.multiplicationInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateVectorScalarToVectorCases(
+ sparseVectorF16Range(dim),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ multiplicationVectorScalarInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarVectorToVectorCases(
+ sparseScalarF16Range(),
+ sparseVectorF16Range(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ multiplicationScalarVectorInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f16_multiplication', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f16_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_multiplication.spec.ts
index 9af0c2918aa4..005a9a1e64af 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_multiplication.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_multiplication.spec.ts
@@ -5,72 +5,13 @@ Execution Tests for non-matrix f16 multiplication expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF16, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF16Range, sparseVectorF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-const multiplicationVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.f16.toVector(v.map(e => FP.f16.multiplicationInterval(e, s)));
-};
-
-const multiplicationScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.f16.toVector(v.map(e => FP.f16.multiplicationInterval(s, e)));
-};
+import { d } from './f16_multiplication.cache.js';
export const g = makeTestGroup(GPUTest);
-const scalar_cases = ([true, false] as const)
- .map(nonConst => ({
- [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarPairToIntervalCases(
- sparseScalarF16Range(),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.multiplicationInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateVectorScalarToVectorCases(
- sparseVectorF16Range(dim),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- multiplicationVectorScalarInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarVectorToVectorCases(
- sparseScalarF16Range(),
- sparseVectorF16Range(dim),
- nonConst ? 'unfiltered' : 'finite',
- multiplicationScalarVectorInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f16_multiplication', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f16_remainder.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_remainder.cache.ts
new file mode 100644
index 000000000000..2c1cdc0c38b4
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_remainder.cache.ts
@@ -0,0 +1,60 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF16Range, sparseVectorF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const remainderVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.f16.toVector(v.map(e => FP.f16.remainderInterval(e, s)));
+};
+
+const remainderScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.f16.toVector(v.map(e => FP.f16.remainderInterval(s, e)));
+};
+
+const scalar_cases = ([true, false] as const)
+ .map(nonConst => ({
+ [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarPairToIntervalCases(
+ sparseScalarF16Range(),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.remainderInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateVectorScalarToVectorCases(
+ sparseVectorF16Range(dim),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ remainderVectorScalarInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarVectorToVectorCases(
+ sparseScalarF16Range(),
+ sparseVectorF16Range(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ remainderScalarVectorInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f16_remainder', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f16_remainder.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_remainder.spec.ts
index e7f10daf4eb8..c2f5cd7af11f 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_remainder.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_remainder.spec.ts
@@ -5,72 +5,13 @@ Execution Tests for non-matrix f16 remainder expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF16, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF16Range, sparseVectorF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-const remainderVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.f16.toVector(v.map(e => FP.f16.remainderInterval(e, s)));
-};
-
-const remainderScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.f16.toVector(v.map(e => FP.f16.remainderInterval(s, e)));
-};
+import { d } from './f16_remainder.cache.js';
export const g = makeTestGroup(GPUTest);
-const scalar_cases = ([true, false] as const)
- .map(nonConst => ({
- [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarPairToIntervalCases(
- sparseScalarF16Range(),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.remainderInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateVectorScalarToVectorCases(
- sparseVectorF16Range(dim),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- remainderVectorScalarInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarVectorToVectorCases(
- sparseScalarF16Range(),
- sparseVectorF16Range(dim),
- nonConst ? 'unfiltered' : 'finite',
- remainderScalarVectorInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f16_remainder', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f16_subtraction.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_subtraction.cache.ts
new file mode 100644
index 000000000000..a68b58449b33
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f16_subtraction.cache.ts
@@ -0,0 +1,60 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF16Range, sparseVectorF16Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const subtractionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.f16.toVector(v.map(e => FP.f16.subtractionInterval(e, s)));
+};
+
+const subtractionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.f16.toVector(v.map(e => FP.f16.subtractionInterval(s, e)));
+};
+
+const scalar_cases = ([true, false] as const)
+ .map(nonConst => ({
+ [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarPairToIntervalCases(
+ sparseScalarF16Range(),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.subtractionInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateVectorScalarToVectorCases(
+ sparseVectorF16Range(dim),
+ sparseScalarF16Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ subtractionVectorScalarInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateScalarVectorToVectorCases(
+ sparseScalarF16Range(),
+ sparseVectorF16Range(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ subtractionScalarVectorInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f16_subtraction', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f16_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_subtraction.spec.ts
index 923c95d40108..a458885ae8ce 100644
--- a/src/webgpu/shader/execution/expression/binary/f16_subtraction.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f16_subtraction.spec.ts
@@ -5,72 +5,13 @@ Execution Tests for non-matrix f16 subtraction expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF16, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF16Range, sparseVectorF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-const subtractionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.f16.toVector(v.map(e => FP.f16.subtractionInterval(e, s)));
-};
-
-const subtractionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.f16.toVector(v.map(e => FP.f16.subtractionInterval(s, e)));
-};
+import { d } from './f16_subtraction.cache.js';
export const g = makeTestGroup(GPUTest);
-const scalar_cases = ([true, false] as const)
- .map(nonConst => ({
- [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarPairToIntervalCases(
- sparseScalarF16Range(),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.subtractionInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateVectorScalarToVectorCases(
- sparseVectorF16Range(dim),
- sparseScalarF16Range(),
- nonConst ? 'unfiltered' : 'finite',
- subtractionVectorScalarInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateScalarVectorToVectorCases(
- sparseScalarF16Range(),
- sparseVectorF16Range(dim),
- nonConst ? 'unfiltered' : 'finite',
- subtractionScalarVectorInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f16_subtraction', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_addition.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_addition.cache.ts
new file mode 100644
index 000000000000..9353671fb028
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_addition.cache.ts
@@ -0,0 +1,60 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF32Range, sparseVectorF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const additionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.f32.toVector(v.map(e => FP.f32.additionInterval(e, s)));
+};
+
+const additionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.f32.toVector(v.map(e => FP.f32.additionInterval(s, e)));
+};
+
+const scalar_cases = ([true, false] as const)
+ .map(nonConst => ({
+ [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarPairToIntervalCases(
+ sparseScalarF32Range(),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.additionInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateVectorScalarToVectorCases(
+ sparseVectorF32Range(dim),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ additionVectorScalarInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarVectorToVectorCases(
+ sparseScalarF32Range(),
+ sparseVectorF32Range(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ additionScalarVectorInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f32_addition', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f32_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_addition.spec.ts
index 772ec272e93f..6bd8b0e7bdb7 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_addition.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_addition.spec.ts
@@ -5,72 +5,13 @@ Execution Tests for non-matrix f32 addition expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF32, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF32Range, sparseVectorF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-const additionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.f32.toVector(v.map(e => FP.f32.additionInterval(e, s)));
-};
-
-const additionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.f32.toVector(v.map(e => FP.f32.additionInterval(s, e)));
-};
+import { d } from './f32_addition.cache.js';
export const g = makeTestGroup(GPUTest);
-const scalar_cases = ([true, false] as const)
- .map(nonConst => ({
- [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarPairToIntervalCases(
- sparseScalarF32Range(),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.additionInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateVectorScalarToVectorCases(
- sparseVectorF32Range(dim),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- additionVectorScalarInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarVectorToVectorCases(
- sparseScalarF32Range(),
- sparseVectorF32Range(dim),
- nonConst ? 'unfiltered' : 'finite',
- additionScalarVectorInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f32_addition', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_comparison.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_comparison.cache.ts
new file mode 100644
index 000000000000..4c16fc55f0e5
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_comparison.cache.ts
@@ -0,0 +1,144 @@
+import { anyOf } from '../../../../util/compare.js';
+import { bool, f32, Scalar } from '../../../../util/conversion.js';
+import { flushSubnormalNumberF32, vectorF32Range } from '../../../../util/math.js';
+import { Case } from '../case.js';
+import { makeCaseCache } from '../case_cache.js';
+
+/**
+ * @returns a test case for the provided left hand & right hand values and truth function.
+ * Handles quantization and subnormals.
+ */
+function makeCase(
+ lhs: number,
+ rhs: number,
+ truthFunc: (lhs: Scalar, rhs: Scalar) => boolean
+): Case {
+ // Subnormal float values may be flushed at any time.
+ // https://www.w3.org/TR/WGSL/#floating-point-evaluation
+ const f32_lhs = f32(lhs);
+ const f32_rhs = f32(rhs);
+ const lhs_options = new Set([f32_lhs, f32(flushSubnormalNumberF32(lhs))]);
+ const rhs_options = new Set([f32_rhs, f32(flushSubnormalNumberF32(rhs))]);
+ const expected: Array = [];
+ lhs_options.forEach(l => {
+ rhs_options.forEach(r => {
+ const result = bool(truthFunc(l, r));
+ if (!expected.includes(result)) {
+ expected.push(result);
+ }
+ });
+ });
+
+ return { input: [f32_lhs, f32_rhs], expected: anyOf(...expected) };
+}
+
+export const d = makeCaseCache('binary/f32_logical', {
+ equals_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) === (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ equals_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) === (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ not_equals_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) !== (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ not_equals_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) !== (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ less_than_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) < (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ less_than_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) < (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ less_equals_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) <= (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ less_equals_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) <= (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ greater_than_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) > (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ greater_than_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) > (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ greater_equals_non_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) >= (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+ greater_equals_const: () => {
+ const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
+ return (lhs.value as number) >= (rhs.value as number);
+ };
+
+ return vectorF32Range(2).map(v => {
+ return makeCase(v[0], v[1], truthFunc);
+ });
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f32_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_comparison.spec.ts
index ef862e7757a0..e5833a0f9f33 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_comparison.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_comparison.spec.ts
@@ -4,155 +4,14 @@ Execution Tests for the f32 comparison operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { anyOf } from '../../../../util/compare.js';
-import { bool, f32, Scalar, TypeBool, TypeF32 } from '../../../../util/conversion.js';
-import { flushSubnormalNumberF32, vectorF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, Case, run } from '../expression.js';
+import { TypeBool, TypeF32 } from '../../../../util/conversion.js';
+import { allInputSources, run } from '../expression.js';
import { binary } from './binary.js';
+import { d } from './f32_comparison.cache.js';
export const g = makeTestGroup(GPUTest);
-/**
- * @returns a test case for the provided left hand & right hand values and truth function.
- * Handles quantization and subnormals.
- */
-function makeCase(
- lhs: number,
- rhs: number,
- truthFunc: (lhs: Scalar, rhs: Scalar) => boolean
-): Case {
- // Subnormal float values may be flushed at any time.
- // https://www.w3.org/TR/WGSL/#floating-point-evaluation
- const f32_lhs = f32(lhs);
- const f32_rhs = f32(rhs);
- const lhs_options = new Set([f32_lhs, f32(flushSubnormalNumberF32(lhs))]);
- const rhs_options = new Set([f32_rhs, f32(flushSubnormalNumberF32(rhs))]);
- const expected: Array = [];
- lhs_options.forEach(l => {
- rhs_options.forEach(r => {
- const result = bool(truthFunc(l, r));
- if (!expected.includes(result)) {
- expected.push(result);
- }
- });
- });
-
- return { input: [f32_lhs, f32_rhs], expected: anyOf(...expected) };
-}
-
-export const d = makeCaseCache('binary/f32_logical', {
- equals_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) === (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- equals_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) === (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- not_equals_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) !== (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- not_equals_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) !== (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- less_than_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) < (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- less_than_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) < (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- less_equals_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) <= (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- less_equals_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) <= (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- greater_than_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) > (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- greater_than_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) > (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- greater_equals_non_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) >= (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
- greater_equals_const: () => {
- const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => {
- return (lhs.value as number) >= (rhs.value as number);
- };
-
- return vectorF32Range(2).map(v => {
- return makeCase(v[0], v[1], truthFunc);
- });
- },
-});
-
g.test('equals')
.specURL('https://www.w3.org/TR/WGSL/#comparison-expr')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_division.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_division.cache.ts
new file mode 100644
index 000000000000..017f7a451a3f
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_division.cache.ts
@@ -0,0 +1,60 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF32Range, sparseVectorF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const divisionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.f32.toVector(v.map(e => FP.f32.divisionInterval(e, s)));
+};
+
+const divisionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.f32.toVector(v.map(e => FP.f32.divisionInterval(s, e)));
+};
+
+const scalar_cases = ([true, false] as const)
+ .map(nonConst => ({
+ [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarPairToIntervalCases(
+ sparseScalarF32Range(),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.divisionInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateVectorScalarToVectorCases(
+ sparseVectorF32Range(dim),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ divisionVectorScalarInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarVectorToVectorCases(
+ sparseScalarF32Range(),
+ sparseVectorF32Range(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ divisionScalarVectorInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f32_division', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f32_division.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_division.spec.ts
index ecbf7e4fd7dc..0c8dd293f57d 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_division.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_division.spec.ts
@@ -5,72 +5,13 @@ Execution Tests for non-matrix f32 division expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF32, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF32Range, sparseVectorF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-const divisionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.f32.toVector(v.map(e => FP.f32.divisionInterval(e, s)));
-};
-
-const divisionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.f32.toVector(v.map(e => FP.f32.divisionInterval(s, e)));
-};
+import { d } from './f32_division.cache.js';
export const g = makeTestGroup(GPUTest);
-const scalar_cases = ([true, false] as const)
- .map(nonConst => ({
- [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarPairToIntervalCases(
- sparseScalarF32Range(),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.divisionInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateVectorScalarToVectorCases(
- sparseVectorF32Range(dim),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- divisionVectorScalarInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarVectorToVectorCases(
- sparseScalarF32Range(),
- sparseVectorF32Range(dim),
- nonConst ? 'unfiltered' : 'finite',
- divisionScalarVectorInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f32_division', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.cache.ts
new file mode 100644
index 000000000000..0f3ced975d12
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.cache.ts
@@ -0,0 +1,23 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matCxR_[non_]const
+const mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateMatrixPairToMatrixCases(
+ sparseMatrixF32Range(cols, rows),
+ sparseMatrixF32Range(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.additionMatrixMatrixInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f32_matrix_addition', mat_cases);
diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.spec.ts
index 9f11c3cac19d..4fcb4d08927d 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.spec.ts
@@ -5,35 +5,13 @@ Execution Tests for matrix f32 addition expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF32, TypeMat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseMatrixF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
+import { d } from './f32_matrix_addition.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matCxR_[non_]const
-const mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateMatrixPairToMatrixCases(
- sparseMatrixF32Range(cols, rows),
- sparseMatrixF32Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.additionMatrixMatrixInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f32_matrix_addition', mat_cases);
-
g.test('matrix')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.cache.ts
new file mode 100644
index 000000000000..cde2d74fdfbe
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.cache.ts
@@ -0,0 +1,25 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matKxR_matCxK_[non_]const
+const mat_mat_cases = ([2, 3, 4] as const)
+ .flatMap(k =>
+ ([2, 3, 4] as const).flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`mat${k}x${rows}_mat${cols}x${k}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateMatrixPairToMatrixCases(
+ sparseMatrixF32Range(k, rows),
+ sparseMatrixF32Range(cols, k),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.multiplicationMatrixMatrixInterval
+ );
+ },
+ }))
+ )
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f32_matrix_matrix_multiplication', mat_mat_cases);
diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.spec.ts
index 2c48eab1872c..ad34d642d26e 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.spec.ts
@@ -5,37 +5,13 @@ Execution Tests for matrix-matrix f32 multiplication expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF32, TypeMat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseMatrixF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
+import { d } from './f32_matrix_matrix_multiplication.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matKxR_matCxK_[non_]const
-const mat_mat_cases = ([2, 3, 4] as const)
- .flatMap(k =>
- ([2, 3, 4] as const).flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`mat${k}x${rows}_mat${cols}x${k}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateMatrixPairToMatrixCases(
- sparseMatrixF32Range(k, rows),
- sparseMatrixF32Range(cols, k),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.multiplicationMatrixMatrixInterval
- );
- },
- }))
- )
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f32_matrix_matrix_multiplication', mat_mat_cases);
-
g.test('matrix_matrix')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.cache.ts
new file mode 100644
index 000000000000..f17dac31e6a9
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.cache.ts
@@ -0,0 +1,44 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF32Range, sparseScalarF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matCxR_scalar_[non_]const
+const mat_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`mat${cols}x${rows}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateMatrixScalarToMatrixCases(
+ sparseMatrixF32Range(cols, rows),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.multiplicationMatrixScalarInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: scalar_matCxR_[non_]const
+const scalar_mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarMatrixToMatrixCases(
+ sparseScalarF32Range(),
+ sparseMatrixF32Range(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.multiplicationScalarMatrixInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f32_matrix_scalar_multiplication', {
+ ...mat_scalar_cases,
+ ...scalar_mat_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.spec.ts
index 8f50c7781688..0558862d065d 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.spec.ts
@@ -5,56 +5,13 @@ Execution Tests for matrix-scalar and scalar-matrix f32 multiplication expressio
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF32, TypeMat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseScalarF32Range, sparseMatrixF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
+import { d } from './f32_matrix_scalar_multiplication.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matCxR_scalar_[non_]const
-const mat_scalar_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`mat${cols}x${rows}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateMatrixScalarToMatrixCases(
- sparseMatrixF32Range(cols, rows),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.multiplicationMatrixScalarInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: scalar_matCxR_[non_]const
-const scalar_mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarMatrixToMatrixCases(
- sparseScalarF32Range(),
- sparseMatrixF32Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.multiplicationScalarMatrixInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f32_matrix_scalar_multiplication', {
- ...mat_scalar_cases,
- ...scalar_mat_cases,
-});
-
g.test('matrix_scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.cache.ts
new file mode 100644
index 000000000000..2cd2bc1c6d22
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.cache.ts
@@ -0,0 +1,23 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matCxR_[non_]const
+const mat_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateMatrixPairToMatrixCases(
+ sparseMatrixF32Range(cols, rows),
+ sparseMatrixF32Range(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.subtractionMatrixMatrixInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f32_matrix_subtraction', mat_cases);
diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.spec.ts
index 5f101d9b270f..8bcf9a47895c 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.spec.ts
@@ -5,35 +5,13 @@ Execution Tests for matrix f32 subtraction expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF32, TypeMat } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseMatrixF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
+import { d } from './f32_matrix_subtraction.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matCxR_[non_]const
-const mat_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateMatrixPairToMatrixCases(
- sparseMatrixF32Range(cols, rows),
- sparseMatrixF32Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.subtractionMatrixMatrixInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f32_matrix_subtraction', mat_cases);
-
g.test('matrix')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.cache.ts
new file mode 100644
index 000000000000..f20b95029e2e
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.cache.ts
@@ -0,0 +1,44 @@
+import { FP } from '../../../../util/floating_point.js';
+import { sparseMatrixF32Range, sparseVectorF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+// Cases: matCxR_vecC_[non_]const
+const mat_vec_cases = ([2, 3, 4] as const)
+ .flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`mat${cols}x${rows}_vec${cols}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateMatrixVectorToVectorCases(
+ sparseMatrixF32Range(cols, rows),
+ sparseVectorF32Range(cols),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.multiplicationMatrixVectorInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: vecR_matCxR_[non_]const
+const vec_mat_cases = ([2, 3, 4] as const)
+ .flatMap(rows =>
+ ([2, 3, 4] as const).flatMap(cols =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${rows}_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateVectorMatrixToVectorCases(
+ sparseVectorF32Range(rows),
+ sparseMatrixF32Range(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.multiplicationVectorMatrixInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f32_matrix_vector_multiplication', {
+ ...mat_vec_cases,
+ ...vec_mat_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.spec.ts
index e6cdf16d9240..a04a28cfeff3 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.spec.ts
@@ -5,56 +5,13 @@ Execution Tests for matrix-vector and vector-matrix f32 multiplication expressio
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF32, TypeMat, TypeVec } from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import { sparseMatrixF32Range, sparseVectorF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
+import { d } from './f32_matrix_vector_multiplication.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: matCxR_vecC_[non_]const
-const mat_vec_cases = ([2, 3, 4] as const)
- .flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`mat${cols}x${rows}_vec${cols}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateMatrixVectorToVectorCases(
- sparseMatrixF32Range(cols, rows),
- sparseVectorF32Range(cols),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.multiplicationMatrixVectorInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: vecR_matCxR_[non_]const
-const vec_mat_cases = ([2, 3, 4] as const)
- .flatMap(rows =>
- ([2, 3, 4] as const).flatMap(cols =>
- ([true, false] as const).map(nonConst => ({
- [`vec${rows}_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateVectorMatrixToVectorCases(
- sparseVectorF32Range(rows),
- sparseMatrixF32Range(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.multiplicationVectorMatrixInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f32_matrix_vector_multiplication', {
- ...mat_vec_cases,
- ...vec_mat_cases,
-});
-
g.test('matrix_vector')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_multiplication.cache.ts
new file mode 100644
index 000000000000..6a8c0bd81e9d
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_multiplication.cache.ts
@@ -0,0 +1,60 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF32Range, sparseVectorF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const multiplicationVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.f32.toVector(v.map(e => FP.f32.multiplicationInterval(e, s)));
+};
+
+const multiplicationScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.f32.toVector(v.map(e => FP.f32.multiplicationInterval(s, e)));
+};
+
+const scalar_cases = ([true, false] as const)
+ .map(nonConst => ({
+ [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarPairToIntervalCases(
+ sparseScalarF32Range(),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.multiplicationInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateVectorScalarToVectorCases(
+ sparseVectorF32Range(dim),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ multiplicationVectorScalarInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarVectorToVectorCases(
+ sparseScalarF32Range(),
+ sparseVectorF32Range(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ multiplicationScalarVectorInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f32_multiplication', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f32_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_multiplication.spec.ts
index 1c0da8ed19f5..77e670795d2d 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_multiplication.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_multiplication.spec.ts
@@ -5,72 +5,13 @@ Execution Tests for non-matrix f32 multiplication expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF32, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF32Range, sparseVectorF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-const multiplicationVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.f32.toVector(v.map(e => FP.f32.multiplicationInterval(e, s)));
-};
-
-const multiplicationScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.f32.toVector(v.map(e => FP.f32.multiplicationInterval(s, e)));
-};
+import { d } from './f32_multiplication.cache.js';
export const g = makeTestGroup(GPUTest);
-const scalar_cases = ([true, false] as const)
- .map(nonConst => ({
- [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarPairToIntervalCases(
- sparseScalarF32Range(),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.multiplicationInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateVectorScalarToVectorCases(
- sparseVectorF32Range(dim),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- multiplicationVectorScalarInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarVectorToVectorCases(
- sparseScalarF32Range(),
- sparseVectorF32Range(dim),
- nonConst ? 'unfiltered' : 'finite',
- multiplicationScalarVectorInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f32_multiplication', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_remainder.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_remainder.cache.ts
new file mode 100644
index 000000000000..2cb1a16f9dcc
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_remainder.cache.ts
@@ -0,0 +1,64 @@
+export const description = `
+Execution Tests for non-matrix f32 remainder expression
+`;
+
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF32Range, sparseVectorF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const remainderVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.f32.toVector(v.map(e => FP.f32.remainderInterval(e, s)));
+};
+
+const remainderScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.f32.toVector(v.map(e => FP.f32.remainderInterval(s, e)));
+};
+
+const scalar_cases = ([true, false] as const)
+ .map(nonConst => ({
+ [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarPairToIntervalCases(
+ sparseScalarF32Range(),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.remainderInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateVectorScalarToVectorCases(
+ sparseVectorF32Range(dim),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ remainderVectorScalarInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarVectorToVectorCases(
+ sparseScalarF32Range(),
+ sparseVectorF32Range(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ remainderScalarVectorInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f32_remainder', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f32_remainder.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_remainder.spec.ts
index 3add756dfd66..b61d3ecc633a 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_remainder.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_remainder.spec.ts
@@ -5,72 +5,13 @@ Execution Tests for non-matrix f32 remainder expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF32, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF32Range, sparseVectorF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-const remainderVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.f32.toVector(v.map(e => FP.f32.remainderInterval(e, s)));
-};
-
-const remainderScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.f32.toVector(v.map(e => FP.f32.remainderInterval(s, e)));
-};
+import { d } from './f32_remainder.cache.js';
export const g = makeTestGroup(GPUTest);
-const scalar_cases = ([true, false] as const)
- .map(nonConst => ({
- [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarPairToIntervalCases(
- sparseScalarF32Range(),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.remainderInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateVectorScalarToVectorCases(
- sparseVectorF32Range(dim),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- remainderVectorScalarInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarVectorToVectorCases(
- sparseScalarF32Range(),
- sparseVectorF32Range(dim),
- nonConst ? 'unfiltered' : 'finite',
- remainderScalarVectorInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f32_remainder', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/f32_subtraction.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_subtraction.cache.ts
new file mode 100644
index 000000000000..519c0b37833d
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/f32_subtraction.cache.ts
@@ -0,0 +1,60 @@
+import { FP, FPVector } from '../../../../util/floating_point.js';
+import { sparseScalarF32Range, sparseVectorF32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+const subtractionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
+ return FP.f32.toVector(v.map(e => FP.f32.subtractionInterval(e, s)));
+};
+
+const subtractionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
+ return FP.f32.toVector(v.map(e => FP.f32.subtractionInterval(s, e)));
+};
+
+const scalar_cases = ([true, false] as const)
+ .map(nonConst => ({
+ [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarPairToIntervalCases(
+ sparseScalarF32Range(),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.subtractionInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const vector_scalar_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateVectorScalarToVectorCases(
+ sparseVectorF32Range(dim),
+ sparseScalarF32Range(),
+ nonConst ? 'unfiltered' : 'finite',
+ subtractionVectorScalarInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+const scalar_vector_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateScalarVectorToVectorCases(
+ sparseScalarF32Range(),
+ sparseVectorF32Range(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ subtractionScalarVectorInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('binary/f32_subtraction', {
+ ...scalar_cases,
+ ...vector_scalar_cases,
+ ...scalar_vector_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/binary/f32_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_subtraction.spec.ts
index 2870a14177b7..e873c6ebc3b1 100644
--- a/src/webgpu/shader/execution/expression/binary/f32_subtraction.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/f32_subtraction.spec.ts
@@ -5,72 +5,13 @@ Execution Tests for non-matrix f32 subtraction expression
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeF32, TypeVec } from '../../../../util/conversion.js';
-import { FP, FPVector } from '../../../../util/floating_point.js';
-import { sparseScalarF32Range, sparseVectorF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-const subtractionVectorScalarInterval = (v: readonly number[], s: number): FPVector => {
- return FP.f32.toVector(v.map(e => FP.f32.subtractionInterval(e, s)));
-};
-
-const subtractionScalarVectorInterval = (s: number, v: readonly number[]): FPVector => {
- return FP.f32.toVector(v.map(e => FP.f32.subtractionInterval(s, e)));
-};
+import { d } from './f32_subtraction.cache.js';
export const g = makeTestGroup(GPUTest);
-const scalar_cases = ([true, false] as const)
- .map(nonConst => ({
- [`scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarPairToIntervalCases(
- sparseScalarF32Range(),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.subtractionInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const vector_scalar_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateVectorScalarToVectorCases(
- sparseVectorF32Range(dim),
- sparseScalarF32Range(),
- nonConst ? 'unfiltered' : 'finite',
- subtractionVectorScalarInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-const scalar_vector_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`scalar_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateScalarVectorToVectorCases(
- sparseScalarF32Range(),
- sparseVectorF32Range(dim),
- nonConst ? 'unfiltered' : 'finite',
- subtractionScalarVectorInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('binary/f32_subtraction', {
- ...scalar_cases,
- ...vector_scalar_cases,
- ...scalar_vector_cases,
-});
-
g.test('scalar')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/i32_arithmetic.cache.ts b/src/webgpu/shader/execution/expression/binary/i32_arithmetic.cache.ts
new file mode 100644
index 000000000000..ca7ca879f52a
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/i32_arithmetic.cache.ts
@@ -0,0 +1,306 @@
+import { kValue } from '../../../../util/constants.js';
+import { sparseI32Range, vectorI32Range } from '../../../../util/math.js';
+import {
+ generateBinaryToI32Cases,
+ generateI32VectorBinaryToVectorCases,
+ generateVectorI32BinaryToVectorCases,
+} from '../case.js';
+import { makeCaseCache } from '../case_cache.js';
+
+function i32_add(x: number, y: number): number | undefined {
+ return x + y;
+}
+
+function i32_subtract(x: number, y: number): number | undefined {
+ return x - y;
+}
+
+function i32_multiply(x: number, y: number): number | undefined {
+ return Math.imul(x, y);
+}
+
+function i32_divide_non_const(x: number, y: number): number | undefined {
+ if (y === 0) {
+ return x;
+ }
+ if (x === kValue.i32.negative.min && y === -1) {
+ return x;
+ }
+ return x / y;
+}
+
+function i32_divide_const(x: number, y: number): number | undefined {
+ if (y === 0) {
+ return undefined;
+ }
+ if (x === kValue.i32.negative.min && y === -1) {
+ return undefined;
+ }
+ return x / y;
+}
+
+function i32_remainder_non_const(x: number, y: number): number | undefined {
+ if (y === 0) {
+ return 0;
+ }
+ if (x === kValue.i32.negative.min && y === -1) {
+ return 0;
+ }
+ return x % y;
+}
+
+function i32_remainder_const(x: number, y: number): number | undefined {
+ if (y === 0) {
+ return undefined;
+ }
+ if (x === kValue.i32.negative.min && y === -1) {
+ return undefined;
+ }
+ return x % y;
+}
+
+export const d = makeCaseCache('binary/i32_arithmetic', {
+ addition: () => {
+ return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_add);
+ },
+ subtraction: () => {
+ return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_subtract);
+ },
+ multiplication: () => {
+ return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_multiply);
+ },
+ division_non_const: () => {
+ return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_divide_non_const);
+ },
+ division_const: () => {
+ return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_divide_const);
+ },
+ remainder_non_const: () => {
+ return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_remainder_non_const);
+ },
+ remainder_const: () => {
+ return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_remainder_const);
+ },
+ addition_scalar_vector2: () => {
+ return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(2), i32_add);
+ },
+ addition_scalar_vector3: () => {
+ return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(3), i32_add);
+ },
+ addition_scalar_vector4: () => {
+ return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(4), i32_add);
+ },
+ addition_vector2_scalar: () => {
+ return generateVectorI32BinaryToVectorCases(vectorI32Range(2), sparseI32Range(), i32_add);
+ },
+ addition_vector3_scalar: () => {
+ return generateVectorI32BinaryToVectorCases(vectorI32Range(3), sparseI32Range(), i32_add);
+ },
+ addition_vector4_scalar: () => {
+ return generateVectorI32BinaryToVectorCases(vectorI32Range(4), sparseI32Range(), i32_add);
+ },
+ subtraction_scalar_vector2: () => {
+ return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(2), i32_subtract);
+ },
+ subtraction_scalar_vector3: () => {
+ return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(3), i32_subtract);
+ },
+ subtraction_scalar_vector4: () => {
+ return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(4), i32_subtract);
+ },
+ subtraction_vector2_scalar: () => {
+ return generateVectorI32BinaryToVectorCases(vectorI32Range(2), sparseI32Range(), i32_subtract);
+ },
+ subtraction_vector3_scalar: () => {
+ return generateVectorI32BinaryToVectorCases(vectorI32Range(3), sparseI32Range(), i32_subtract);
+ },
+ subtraction_vector4_scalar: () => {
+ return generateVectorI32BinaryToVectorCases(vectorI32Range(4), sparseI32Range(), i32_subtract);
+ },
+ multiplication_scalar_vector2: () => {
+ return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(2), i32_multiply);
+ },
+ multiplication_scalar_vector3: () => {
+ return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(3), i32_multiply);
+ },
+ multiplication_scalar_vector4: () => {
+ return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(4), i32_multiply);
+ },
+ multiplication_vector2_scalar: () => {
+ return generateVectorI32BinaryToVectorCases(vectorI32Range(2), sparseI32Range(), i32_multiply);
+ },
+ multiplication_vector3_scalar: () => {
+ return generateVectorI32BinaryToVectorCases(vectorI32Range(3), sparseI32Range(), i32_multiply);
+ },
+ multiplication_vector4_scalar: () => {
+ return generateVectorI32BinaryToVectorCases(vectorI32Range(4), sparseI32Range(), i32_multiply);
+ },
+ division_scalar_vector2_non_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(2),
+ i32_divide_non_const
+ );
+ },
+ division_scalar_vector3_non_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(3),
+ i32_divide_non_const
+ );
+ },
+ division_scalar_vector4_non_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(4),
+ i32_divide_non_const
+ );
+ },
+ division_vector2_scalar_non_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(2),
+ sparseI32Range(),
+ i32_divide_non_const
+ );
+ },
+ division_vector3_scalar_non_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(3),
+ sparseI32Range(),
+ i32_divide_non_const
+ );
+ },
+ division_vector4_scalar_non_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(4),
+ sparseI32Range(),
+ i32_divide_non_const
+ );
+ },
+ division_scalar_vector2_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(2),
+ i32_divide_const
+ );
+ },
+ division_scalar_vector3_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(3),
+ i32_divide_const
+ );
+ },
+ division_scalar_vector4_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(4),
+ i32_divide_const
+ );
+ },
+ division_vector2_scalar_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(2),
+ sparseI32Range(),
+ i32_divide_const
+ );
+ },
+ division_vector3_scalar_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(3),
+ sparseI32Range(),
+ i32_divide_const
+ );
+ },
+ division_vector4_scalar_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(4),
+ sparseI32Range(),
+ i32_divide_const
+ );
+ },
+ remainder_scalar_vector2_non_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(2),
+ i32_remainder_non_const
+ );
+ },
+ remainder_scalar_vector3_non_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(3),
+ i32_remainder_non_const
+ );
+ },
+ remainder_scalar_vector4_non_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(4),
+ i32_remainder_non_const
+ );
+ },
+ remainder_vector2_scalar_non_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(2),
+ sparseI32Range(),
+ i32_remainder_non_const
+ );
+ },
+ remainder_vector3_scalar_non_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(3),
+ sparseI32Range(),
+ i32_remainder_non_const
+ );
+ },
+ remainder_vector4_scalar_non_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(4),
+ sparseI32Range(),
+ i32_remainder_non_const
+ );
+ },
+ remainder_scalar_vector2_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(2),
+ i32_remainder_const
+ );
+ },
+ remainder_scalar_vector3_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(3),
+ i32_remainder_const
+ );
+ },
+ remainder_scalar_vector4_const: () => {
+ return generateI32VectorBinaryToVectorCases(
+ sparseI32Range(),
+ vectorI32Range(4),
+ i32_remainder_const
+ );
+ },
+ remainder_vector2_scalar_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(2),
+ sparseI32Range(),
+ i32_remainder_const
+ );
+ },
+ remainder_vector3_scalar_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(3),
+ sparseI32Range(),
+ i32_remainder_const
+ );
+ },
+ remainder_vector4_scalar_const: () => {
+ return generateVectorI32BinaryToVectorCases(
+ vectorI32Range(4),
+ sparseI32Range(),
+ i32_remainder_const
+ );
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts
index e9b7a2407fb2..ef201f66689f 100644
--- a/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts
@@ -4,320 +4,14 @@ Execution Tests for the i32 arithmetic binary expression operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { kValue } from '../../../../util/constants.js';
import { TypeI32, TypeVec } from '../../../../util/conversion.js';
-import { sparseI32Range, vectorI32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import {
- allInputSources,
- generateBinaryToI32Cases,
- generateI32VectorBinaryToVectorCases,
- generateVectorI32BinaryToVectorCases,
- run,
-} from '../expression.js';
+import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-function i32_add(x: number, y: number): number | undefined {
- return x + y;
-}
-
-function i32_subtract(x: number, y: number): number | undefined {
- return x - y;
-}
-
-function i32_multiply(x: number, y: number): number | undefined {
- return Math.imul(x, y);
-}
-
-function i32_divide_non_const(x: number, y: number): number | undefined {
- if (y === 0) {
- return x;
- }
- if (x === kValue.i32.negative.min && y === -1) {
- return x;
- }
- return x / y;
-}
-
-function i32_divide_const(x: number, y: number): number | undefined {
- if (y === 0) {
- return undefined;
- }
- if (x === kValue.i32.negative.min && y === -1) {
- return undefined;
- }
- return x / y;
-}
-
-function i32_remainder_non_const(x: number, y: number): number | undefined {
- if (y === 0) {
- return 0;
- }
- if (x === kValue.i32.negative.min && y === -1) {
- return 0;
- }
- return x % y;
-}
-
-function i32_remainder_const(x: number, y: number): number | undefined {
- if (y === 0) {
- return undefined;
- }
- if (x === kValue.i32.negative.min && y === -1) {
- return undefined;
- }
- return x % y;
-}
+import { d } from './i32_arithmetic.cache.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('binary/i32_arithmetic', {
- addition: () => {
- return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_add);
- },
- subtraction: () => {
- return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_subtract);
- },
- multiplication: () => {
- return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_multiply);
- },
- division_non_const: () => {
- return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_divide_non_const);
- },
- division_const: () => {
- return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_divide_const);
- },
- remainder_non_const: () => {
- return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_remainder_non_const);
- },
- remainder_const: () => {
- return generateBinaryToI32Cases(sparseI32Range(), sparseI32Range(), i32_remainder_const);
- },
- addition_scalar_vector2: () => {
- return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(2), i32_add);
- },
- addition_scalar_vector3: () => {
- return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(3), i32_add);
- },
- addition_scalar_vector4: () => {
- return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(4), i32_add);
- },
- addition_vector2_scalar: () => {
- return generateVectorI32BinaryToVectorCases(vectorI32Range(2), sparseI32Range(), i32_add);
- },
- addition_vector3_scalar: () => {
- return generateVectorI32BinaryToVectorCases(vectorI32Range(3), sparseI32Range(), i32_add);
- },
- addition_vector4_scalar: () => {
- return generateVectorI32BinaryToVectorCases(vectorI32Range(4), sparseI32Range(), i32_add);
- },
- subtraction_scalar_vector2: () => {
- return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(2), i32_subtract);
- },
- subtraction_scalar_vector3: () => {
- return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(3), i32_subtract);
- },
- subtraction_scalar_vector4: () => {
- return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(4), i32_subtract);
- },
- subtraction_vector2_scalar: () => {
- return generateVectorI32BinaryToVectorCases(vectorI32Range(2), sparseI32Range(), i32_subtract);
- },
- subtraction_vector3_scalar: () => {
- return generateVectorI32BinaryToVectorCases(vectorI32Range(3), sparseI32Range(), i32_subtract);
- },
- subtraction_vector4_scalar: () => {
- return generateVectorI32BinaryToVectorCases(vectorI32Range(4), sparseI32Range(), i32_subtract);
- },
- multiplication_scalar_vector2: () => {
- return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(2), i32_multiply);
- },
- multiplication_scalar_vector3: () => {
- return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(3), i32_multiply);
- },
- multiplication_scalar_vector4: () => {
- return generateI32VectorBinaryToVectorCases(sparseI32Range(), vectorI32Range(4), i32_multiply);
- },
- multiplication_vector2_scalar: () => {
- return generateVectorI32BinaryToVectorCases(vectorI32Range(2), sparseI32Range(), i32_multiply);
- },
- multiplication_vector3_scalar: () => {
- return generateVectorI32BinaryToVectorCases(vectorI32Range(3), sparseI32Range(), i32_multiply);
- },
- multiplication_vector4_scalar: () => {
- return generateVectorI32BinaryToVectorCases(vectorI32Range(4), sparseI32Range(), i32_multiply);
- },
- division_scalar_vector2_non_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(2),
- i32_divide_non_const
- );
- },
- division_scalar_vector3_non_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(3),
- i32_divide_non_const
- );
- },
- division_scalar_vector4_non_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(4),
- i32_divide_non_const
- );
- },
- division_vector2_scalar_non_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(2),
- sparseI32Range(),
- i32_divide_non_const
- );
- },
- division_vector3_scalar_non_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(3),
- sparseI32Range(),
- i32_divide_non_const
- );
- },
- division_vector4_scalar_non_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(4),
- sparseI32Range(),
- i32_divide_non_const
- );
- },
- division_scalar_vector2_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(2),
- i32_divide_const
- );
- },
- division_scalar_vector3_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(3),
- i32_divide_const
- );
- },
- division_scalar_vector4_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(4),
- i32_divide_const
- );
- },
- division_vector2_scalar_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(2),
- sparseI32Range(),
- i32_divide_const
- );
- },
- division_vector3_scalar_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(3),
- sparseI32Range(),
- i32_divide_const
- );
- },
- division_vector4_scalar_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(4),
- sparseI32Range(),
- i32_divide_const
- );
- },
- remainder_scalar_vector2_non_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(2),
- i32_remainder_non_const
- );
- },
- remainder_scalar_vector3_non_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(3),
- i32_remainder_non_const
- );
- },
- remainder_scalar_vector4_non_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(4),
- i32_remainder_non_const
- );
- },
- remainder_vector2_scalar_non_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(2),
- sparseI32Range(),
- i32_remainder_non_const
- );
- },
- remainder_vector3_scalar_non_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(3),
- sparseI32Range(),
- i32_remainder_non_const
- );
- },
- remainder_vector4_scalar_non_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(4),
- sparseI32Range(),
- i32_remainder_non_const
- );
- },
- remainder_scalar_vector2_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(2),
- i32_remainder_const
- );
- },
- remainder_scalar_vector3_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(3),
- i32_remainder_const
- );
- },
- remainder_scalar_vector4_const: () => {
- return generateI32VectorBinaryToVectorCases(
- sparseI32Range(),
- vectorI32Range(4),
- i32_remainder_const
- );
- },
- remainder_vector2_scalar_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(2),
- sparseI32Range(),
- i32_remainder_const
- );
- },
- remainder_vector3_scalar_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(3),
- sparseI32Range(),
- i32_remainder_const
- );
- },
- remainder_vector4_scalar_const: () => {
- return generateVectorI32BinaryToVectorCases(
- vectorI32Range(4),
- sparseI32Range(),
- i32_remainder_const
- );
- },
-});
-
g.test('addition')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/i32_comparison.cache.ts b/src/webgpu/shader/execution/expression/binary/i32_comparison.cache.ts
new file mode 100644
index 000000000000..de0a6de477c3
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/i32_comparison.cache.ts
@@ -0,0 +1,21 @@
+import { bool, i32 } from '../../../../util/conversion.js';
+import { vectorI32Range } from '../../../../util/math.js';
+import { Case } from '../case.js';
+import { makeCaseCache } from '../case_cache.js';
+
+/**
+ * @returns a test case for the provided left hand & right hand values and
+ * expected boolean result.
+ */
+function makeCase(lhs: number, rhs: number, expected_answer: boolean): Case {
+ return { input: [i32(lhs), i32(rhs)], expected: bool(expected_answer) };
+}
+
+export const d = makeCaseCache('binary/i32_comparison', {
+ equals: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] === v[1])),
+ not_equals: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] !== v[1])),
+ less_than: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] < v[1])),
+ less_equal: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] <= v[1])),
+ greater_than: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] > v[1])),
+ greater_equal: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] >= v[1])),
+});
diff --git a/src/webgpu/shader/execution/expression/binary/i32_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/i32_comparison.spec.ts
index dce1a2519ead..c07d09a058ed 100644
--- a/src/webgpu/shader/execution/expression/binary/i32_comparison.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/i32_comparison.spec.ts
@@ -4,32 +4,14 @@ Execution Tests for the i32 comparison expressions
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { i32, bool, TypeBool, TypeI32 } from '../../../../util/conversion.js';
-import { vectorI32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, Case, run } from '../expression.js';
+import { TypeBool, TypeI32 } from '../../../../util/conversion.js';
+import { allInputSources, run } from '../expression.js';
import { binary } from './binary.js';
+import { d } from './i32_comparison.cache.js';
export const g = makeTestGroup(GPUTest);
-/**
- * @returns a test case for the provided left hand & right hand values and
- * expected boolean result.
- */
-function makeCase(lhs: number, rhs: number, expected_answer: boolean): Case {
- return { input: [i32(lhs), i32(rhs)], expected: bool(expected_answer) };
-}
-
-export const d = makeCaseCache('binary/i32_comparison', {
- equals: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] === v[1])),
- not_equals: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] !== v[1])),
- less_than: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] < v[1])),
- less_equal: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] <= v[1])),
- greater_than: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] > v[1])),
- greater_equal: () => vectorI32Range(2).map(v => makeCase(v[0], v[1], v[0] >= v[1])),
-});
-
g.test('equals')
.specURL('https://www.w3.org/TR/WGSL/#comparison-expr')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/u32_arithmetic.cache.ts b/src/webgpu/shader/execution/expression/binary/u32_arithmetic.cache.ts
new file mode 100644
index 000000000000..91be35a1eeff
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/u32_arithmetic.cache.ts
@@ -0,0 +1,293 @@
+import { sparseU32Range, vectorU32Range } from '../../../../util/math.js';
+import {
+ generateBinaryToU32Cases,
+ generateU32VectorBinaryToVectorCases,
+ generateVectorU32BinaryToVectorCases,
+} from '../case.js';
+import { makeCaseCache } from '../case_cache.js';
+
+function u32_add(x: number, y: number): number | undefined {
+ return x + y;
+}
+
+function u32_subtract(x: number, y: number): number | undefined {
+ return x - y;
+}
+
+function u32_multiply(x: number, y: number): number | undefined {
+ return Math.imul(x, y);
+}
+
+function u32_divide_non_const(x: number, y: number): number | undefined {
+ if (y === 0) {
+ return x;
+ }
+ return x / y;
+}
+
+function u32_divide_const(x: number, y: number): number | undefined {
+ if (y === 0) {
+ return undefined;
+ }
+ return x / y;
+}
+
+function u32_remainder_non_const(x: number, y: number): number | undefined {
+ if (y === 0) {
+ return 0;
+ }
+ return x % y;
+}
+
+function u32_remainder_const(x: number, y: number): number | undefined {
+ if (y === 0) {
+ return undefined;
+ }
+ return x % y;
+}
+
+export const d = makeCaseCache('binary/u32_arithmetic', {
+ addition: () => {
+ return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_add);
+ },
+ subtraction: () => {
+ return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_subtract);
+ },
+ multiplication: () => {
+ return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_multiply);
+ },
+ division_non_const: () => {
+ return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_divide_non_const);
+ },
+ division_const: () => {
+ return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_divide_const);
+ },
+ remainder_non_const: () => {
+ return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_remainder_non_const);
+ },
+ remainder_const: () => {
+ return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_remainder_const);
+ },
+ addition_scalar_vector2: () => {
+ return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(2), u32_add);
+ },
+ addition_scalar_vector3: () => {
+ return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(3), u32_add);
+ },
+ addition_scalar_vector4: () => {
+ return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(4), u32_add);
+ },
+ addition_vector2_scalar: () => {
+ return generateVectorU32BinaryToVectorCases(vectorU32Range(2), sparseU32Range(), u32_add);
+ },
+ addition_vector3_scalar: () => {
+ return generateVectorU32BinaryToVectorCases(vectorU32Range(3), sparseU32Range(), u32_add);
+ },
+ addition_vector4_scalar: () => {
+ return generateVectorU32BinaryToVectorCases(vectorU32Range(4), sparseU32Range(), u32_add);
+ },
+ subtraction_scalar_vector2: () => {
+ return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(2), u32_subtract);
+ },
+ subtraction_scalar_vector3: () => {
+ return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(3), u32_subtract);
+ },
+ subtraction_scalar_vector4: () => {
+ return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(4), u32_subtract);
+ },
+ subtraction_vector2_scalar: () => {
+ return generateVectorU32BinaryToVectorCases(vectorU32Range(2), sparseU32Range(), u32_subtract);
+ },
+ subtraction_vector3_scalar: () => {
+ return generateVectorU32BinaryToVectorCases(vectorU32Range(3), sparseU32Range(), u32_subtract);
+ },
+ subtraction_vector4_scalar: () => {
+ return generateVectorU32BinaryToVectorCases(vectorU32Range(4), sparseU32Range(), u32_subtract);
+ },
+ multiplication_scalar_vector2: () => {
+ return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(2), u32_multiply);
+ },
+ multiplication_scalar_vector3: () => {
+ return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(3), u32_multiply);
+ },
+ multiplication_scalar_vector4: () => {
+ return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(4), u32_multiply);
+ },
+ multiplication_vector2_scalar: () => {
+ return generateVectorU32BinaryToVectorCases(vectorU32Range(2), sparseU32Range(), u32_multiply);
+ },
+ multiplication_vector3_scalar: () => {
+ return generateVectorU32BinaryToVectorCases(vectorU32Range(3), sparseU32Range(), u32_multiply);
+ },
+ multiplication_vector4_scalar: () => {
+ return generateVectorU32BinaryToVectorCases(vectorU32Range(4), sparseU32Range(), u32_multiply);
+ },
+ division_scalar_vector2_non_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(2),
+ u32_divide_non_const
+ );
+ },
+ division_scalar_vector3_non_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(3),
+ u32_divide_non_const
+ );
+ },
+ division_scalar_vector4_non_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(4),
+ u32_divide_non_const
+ );
+ },
+ division_vector2_scalar_non_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(2),
+ sparseU32Range(),
+ u32_divide_non_const
+ );
+ },
+ division_vector3_scalar_non_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(3),
+ sparseU32Range(),
+ u32_divide_non_const
+ );
+ },
+ division_vector4_scalar_non_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(4),
+ sparseU32Range(),
+ u32_divide_non_const
+ );
+ },
+ division_scalar_vector2_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(2),
+ u32_divide_const
+ );
+ },
+ division_scalar_vector3_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(3),
+ u32_divide_const
+ );
+ },
+ division_scalar_vector4_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(4),
+ u32_divide_const
+ );
+ },
+ division_vector2_scalar_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(2),
+ sparseU32Range(),
+ u32_divide_const
+ );
+ },
+ division_vector3_scalar_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(3),
+ sparseU32Range(),
+ u32_divide_const
+ );
+ },
+ division_vector4_scalar_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(4),
+ sparseU32Range(),
+ u32_divide_const
+ );
+ },
+ remainder_scalar_vector2_non_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(2),
+ u32_remainder_non_const
+ );
+ },
+ remainder_scalar_vector3_non_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(3),
+ u32_remainder_non_const
+ );
+ },
+ remainder_scalar_vector4_non_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(4),
+ u32_remainder_non_const
+ );
+ },
+ remainder_vector2_scalar_non_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(2),
+ sparseU32Range(),
+ u32_remainder_non_const
+ );
+ },
+ remainder_vector3_scalar_non_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(3),
+ sparseU32Range(),
+ u32_remainder_non_const
+ );
+ },
+ remainder_vector4_scalar_non_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(4),
+ sparseU32Range(),
+ u32_remainder_non_const
+ );
+ },
+ remainder_scalar_vector2_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(2),
+ u32_remainder_const
+ );
+ },
+ remainder_scalar_vector3_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(3),
+ u32_remainder_const
+ );
+ },
+ remainder_scalar_vector4_const: () => {
+ return generateU32VectorBinaryToVectorCases(
+ sparseU32Range(),
+ vectorU32Range(4),
+ u32_remainder_const
+ );
+ },
+ remainder_vector2_scalar_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(2),
+ sparseU32Range(),
+ u32_remainder_const
+ );
+ },
+ remainder_vector3_scalar_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(3),
+ sparseU32Range(),
+ u32_remainder_const
+ );
+ },
+ remainder_vector4_scalar_const: () => {
+ return generateVectorU32BinaryToVectorCases(
+ vectorU32Range(4),
+ sparseU32Range(),
+ u32_remainder_const
+ );
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts
index 88667e823386..28c25fef8dc9 100644
--- a/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts
@@ -5,306 +5,13 @@ Execution Tests for the u32 arithmetic binary expression operations
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
import { TypeU32, TypeVec } from '../../../../util/conversion.js';
-import { sparseU32Range, vectorU32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import {
- allInputSources,
- generateBinaryToU32Cases,
- generateU32VectorBinaryToVectorCases,
- generateVectorU32BinaryToVectorCases,
- run,
-} from '../expression.js';
+import { allInputSources, run } from '../expression.js';
import { binary, compoundBinary } from './binary.js';
-
-function u32_add(x: number, y: number): number | undefined {
- return x + y;
-}
-
-function u32_subtract(x: number, y: number): number | undefined {
- return x - y;
-}
-
-function u32_multiply(x: number, y: number): number | undefined {
- return Math.imul(x, y);
-}
-
-function u32_divide_non_const(x: number, y: number): number | undefined {
- if (y === 0) {
- return x;
- }
- return x / y;
-}
-
-function u32_divide_const(x: number, y: number): number | undefined {
- if (y === 0) {
- return undefined;
- }
- return x / y;
-}
-
-function u32_remainder_non_const(x: number, y: number): number | undefined {
- if (y === 0) {
- return 0;
- }
- return x % y;
-}
-
-function u32_remainder_const(x: number, y: number): number | undefined {
- if (y === 0) {
- return undefined;
- }
- return x % y;
-}
+import { d } from './u32_arithmetic.cache.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('binary/u32_arithmetic', {
- addition: () => {
- return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_add);
- },
- subtraction: () => {
- return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_subtract);
- },
- multiplication: () => {
- return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_multiply);
- },
- division_non_const: () => {
- return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_divide_non_const);
- },
- division_const: () => {
- return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_divide_const);
- },
- remainder_non_const: () => {
- return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_remainder_non_const);
- },
- remainder_const: () => {
- return generateBinaryToU32Cases(sparseU32Range(), sparseU32Range(), u32_remainder_const);
- },
- addition_scalar_vector2: () => {
- return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(2), u32_add);
- },
- addition_scalar_vector3: () => {
- return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(3), u32_add);
- },
- addition_scalar_vector4: () => {
- return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(4), u32_add);
- },
- addition_vector2_scalar: () => {
- return generateVectorU32BinaryToVectorCases(vectorU32Range(2), sparseU32Range(), u32_add);
- },
- addition_vector3_scalar: () => {
- return generateVectorU32BinaryToVectorCases(vectorU32Range(3), sparseU32Range(), u32_add);
- },
- addition_vector4_scalar: () => {
- return generateVectorU32BinaryToVectorCases(vectorU32Range(4), sparseU32Range(), u32_add);
- },
- subtraction_scalar_vector2: () => {
- return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(2), u32_subtract);
- },
- subtraction_scalar_vector3: () => {
- return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(3), u32_subtract);
- },
- subtraction_scalar_vector4: () => {
- return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(4), u32_subtract);
- },
- subtraction_vector2_scalar: () => {
- return generateVectorU32BinaryToVectorCases(vectorU32Range(2), sparseU32Range(), u32_subtract);
- },
- subtraction_vector3_scalar: () => {
- return generateVectorU32BinaryToVectorCases(vectorU32Range(3), sparseU32Range(), u32_subtract);
- },
- subtraction_vector4_scalar: () => {
- return generateVectorU32BinaryToVectorCases(vectorU32Range(4), sparseU32Range(), u32_subtract);
- },
- multiplication_scalar_vector2: () => {
- return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(2), u32_multiply);
- },
- multiplication_scalar_vector3: () => {
- return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(3), u32_multiply);
- },
- multiplication_scalar_vector4: () => {
- return generateU32VectorBinaryToVectorCases(sparseU32Range(), vectorU32Range(4), u32_multiply);
- },
- multiplication_vector2_scalar: () => {
- return generateVectorU32BinaryToVectorCases(vectorU32Range(2), sparseU32Range(), u32_multiply);
- },
- multiplication_vector3_scalar: () => {
- return generateVectorU32BinaryToVectorCases(vectorU32Range(3), sparseU32Range(), u32_multiply);
- },
- multiplication_vector4_scalar: () => {
- return generateVectorU32BinaryToVectorCases(vectorU32Range(4), sparseU32Range(), u32_multiply);
- },
- division_scalar_vector2_non_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(2),
- u32_divide_non_const
- );
- },
- division_scalar_vector3_non_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(3),
- u32_divide_non_const
- );
- },
- division_scalar_vector4_non_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(4),
- u32_divide_non_const
- );
- },
- division_vector2_scalar_non_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(2),
- sparseU32Range(),
- u32_divide_non_const
- );
- },
- division_vector3_scalar_non_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(3),
- sparseU32Range(),
- u32_divide_non_const
- );
- },
- division_vector4_scalar_non_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(4),
- sparseU32Range(),
- u32_divide_non_const
- );
- },
- division_scalar_vector2_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(2),
- u32_divide_const
- );
- },
- division_scalar_vector3_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(3),
- u32_divide_const
- );
- },
- division_scalar_vector4_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(4),
- u32_divide_const
- );
- },
- division_vector2_scalar_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(2),
- sparseU32Range(),
- u32_divide_const
- );
- },
- division_vector3_scalar_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(3),
- sparseU32Range(),
- u32_divide_const
- );
- },
- division_vector4_scalar_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(4),
- sparseU32Range(),
- u32_divide_const
- );
- },
- remainder_scalar_vector2_non_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(2),
- u32_remainder_non_const
- );
- },
- remainder_scalar_vector3_non_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(3),
- u32_remainder_non_const
- );
- },
- remainder_scalar_vector4_non_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(4),
- u32_remainder_non_const
- );
- },
- remainder_vector2_scalar_non_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(2),
- sparseU32Range(),
- u32_remainder_non_const
- );
- },
- remainder_vector3_scalar_non_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(3),
- sparseU32Range(),
- u32_remainder_non_const
- );
- },
- remainder_vector4_scalar_non_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(4),
- sparseU32Range(),
- u32_remainder_non_const
- );
- },
- remainder_scalar_vector2_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(2),
- u32_remainder_const
- );
- },
- remainder_scalar_vector3_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(3),
- u32_remainder_const
- );
- },
- remainder_scalar_vector4_const: () => {
- return generateU32VectorBinaryToVectorCases(
- sparseU32Range(),
- vectorU32Range(4),
- u32_remainder_const
- );
- },
- remainder_vector2_scalar_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(2),
- sparseU32Range(),
- u32_remainder_const
- );
- },
- remainder_vector3_scalar_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(3),
- sparseU32Range(),
- u32_remainder_const
- );
- },
- remainder_vector4_scalar_const: () => {
- return generateVectorU32BinaryToVectorCases(
- vectorU32Range(4),
- sparseU32Range(),
- u32_remainder_const
- );
- },
-});
-
g.test('addition')
.specURL('https://www.w3.org/TR/WGSL/#arithmetic-expr')
.desc(
diff --git a/src/webgpu/shader/execution/expression/binary/u32_comparison.cache.ts b/src/webgpu/shader/execution/expression/binary/u32_comparison.cache.ts
new file mode 100644
index 000000000000..93b05004964d
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/binary/u32_comparison.cache.ts
@@ -0,0 +1,21 @@
+import { bool, u32 } from '../../../../util/conversion.js';
+import { vectorU32Range } from '../../../../util/math.js';
+import { Case } from '../case.js';
+import { makeCaseCache } from '../case_cache.js';
+
+/**
+ * @returns a test case for the provided left hand & right hand values and
+ * expected boolean result.
+ */
+function makeCase(lhs: number, rhs: number, expected_answer: boolean): Case {
+ return { input: [u32(lhs), u32(rhs)], expected: bool(expected_answer) };
+}
+
+export const d = makeCaseCache('binary/u32_comparison', {
+ equals: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] === v[1])),
+ not_equals: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] !== v[1])),
+ less_than: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] < v[1])),
+ less_equal: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] <= v[1])),
+ greater_than: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] > v[1])),
+ greater_equal: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] >= v[1])),
+});
diff --git a/src/webgpu/shader/execution/expression/binary/u32_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/u32_comparison.spec.ts
index 1f693da5fd76..fbf34b510394 100644
--- a/src/webgpu/shader/execution/expression/binary/u32_comparison.spec.ts
+++ b/src/webgpu/shader/execution/expression/binary/u32_comparison.spec.ts
@@ -4,32 +4,14 @@ Execution Tests for the u32 comparison expressions
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../gpu_test.js';
-import { u32, bool, TypeBool, TypeU32 } from '../../../../util/conversion.js';
-import { vectorU32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, Case, run } from '../expression.js';
+import { TypeBool, TypeU32 } from '../../../../util/conversion.js';
+import { allInputSources, run } from '../expression.js';
import { binary } from './binary.js';
+import { d } from './u32_comparison.cache.js';
export const g = makeTestGroup(GPUTest);
-/**
- * @returns a test case for the provided left hand & right hand values and
- * expected boolean result.
- */
-function makeCase(lhs: number, rhs: number, expected_answer: boolean): Case {
- return { input: [u32(lhs), u32(rhs)], expected: bool(expected_answer) };
-}
-
-export const d = makeCaseCache('binary/u32_comparison', {
- equals: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] === v[1])),
- not_equals: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] !== v[1])),
- less_than: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] < v[1])),
- less_equal: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] <= v[1])),
- greater_than: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] > v[1])),
- greater_equal: () => vectorU32Range(2).map(v => makeCase(v[0], v[1], v[0] >= v[1])),
-});
-
g.test('equals')
.specURL('https://www.w3.org/TR/WGSL/#comparison-expr')
.desc(
diff --git a/src/webgpu/shader/execution/expression/call/builtin/abs.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/abs.cache.ts
new file mode 100644
index 000000000000..caed2f469678
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/abs.cache.ts
@@ -0,0 +1,17 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ 'unfiltered',
+ FP[trait].absInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('abs', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/abs.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/abs.spec.ts
index 8f89b1157c4c..b0736cb22fb6 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/abs.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/abs.spec.ts
@@ -27,29 +27,13 @@ import {
u32Bits,
TypeAbstractFloat,
} from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
+import { d } from './abs.cache.js';
import { abstractBuiltin, builtin } from './builtin.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16|abstract]
-const cases = (['f32', 'f16', 'abstract'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- 'unfiltered',
- FP[trait].absInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('abs', cases);
-
g.test('abstract_int')
.specURL('https://www.w3.org/TR/WGSL/#integer-builtin-functions')
.desc(`abstract int tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/acos.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/acos.cache.ts
new file mode 100644
index 000000000000..efe44dcc0c1d
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/acos.cache.ts
@@ -0,0 +1,20 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [...linearRange(-1, 1, 100), ...FP[trait].scalarRange()], // acos is defined on [-1, 1]
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].acosInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('acos', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/acos.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/acos.spec.ts
index 5c865cbd48a4..1d489e1191b8 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/acos.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/acos.spec.ts
@@ -10,32 +10,13 @@ Returns the arc cosine of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, run } from '../../expression.js';
+import { d } from './acos.cache.js';
import { builtin } from './builtin.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [...linearRange(-1, 1, 100), ...FP[trait].scalarRange()], // acos is defined on [-1, 1]
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].acosInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('acos', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/acosh.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/acosh.cache.ts
new file mode 100644
index 000000000000..223f4c96f9b8
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/acosh.cache.ts
@@ -0,0 +1,20 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { biasedRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [...biasedRange(1, 2, 100), ...FP[trait].scalarRange()], // x near 1 can be problematic to implement
+ nonConst ? 'unfiltered' : 'finite',
+ ...FP[trait].acoshIntervals
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('acosh', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/acosh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/acosh.spec.ts
index e5c5eaa6d590..737bd5677241 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/acosh.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/acosh.spec.ts
@@ -13,33 +13,14 @@ Note: The result is not mathematically meaningful when e < 1.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { biasedRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
+import { d } from './acosh.cache.js';
import { builtin } from './builtin.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [...biasedRange(1, 2, 100), ...FP[trait].scalarRange()], // x near 1 can be problematic to implement
- nonConst ? 'unfiltered' : 'finite',
- ...FP[trait].acoshIntervals
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('acosh', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/asin.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/asin.cache.ts
new file mode 100644
index 000000000000..8b71713ac6a3
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/asin.cache.ts
@@ -0,0 +1,20 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [...linearRange(-1, 1, 100), ...FP[trait].scalarRange()], // asin is defined on [-1, 1]
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].asinInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('asin', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/asin.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/asin.spec.ts
index add7f069d1c9..8a7934936030 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/asin.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/asin.spec.ts
@@ -9,33 +9,14 @@ Returns the arc sine of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
+import { d } from './asin.cache.js';
import { builtin } from './builtin.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [...linearRange(-1, 1, 100), ...FP[trait].scalarRange()], // asin is defined on [-1, 1]
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].asinInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('asin', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/asinh.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/asinh.cache.ts
new file mode 100644
index 000000000000..1a42182b97bc
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/asinh.cache.ts
@@ -0,0 +1,17 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]
+const cases = (['f32', 'f16'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ 'unfiltered',
+ FP[trait].asinhInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('asinh', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/asinh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/asinh.spec.ts
index b25edd5f9e67..b5f362066b85 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/asinh.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/asinh.spec.ts
@@ -12,30 +12,14 @@ Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
+import { d } from './asinh.cache.js';
import { builtin } from './builtin.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]
-const cases = (['f32', 'f16'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- 'unfiltered',
- FP[trait].asinhInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('asinh', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float test`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/atan.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/atan.cache.ts
new file mode 100644
index 000000000000..ce2a4e688cfe
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/atan.cache.ts
@@ -0,0 +1,21 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+const known_values = [-Math.sqrt(3), -1, -1 / Math.sqrt(3), 0, 1, 1 / Math.sqrt(3), Math.sqrt(3)];
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [...known_values, ...FP[trait].scalarRange()],
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].atanInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('atan', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/atan.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/atan.spec.ts
index 2b0a50727640..173fb0a0010e 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/atan.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/atan.spec.ts
@@ -10,34 +10,14 @@ Returns the arc tangent of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
+import { d } from './atan.cache.js';
import { builtin } from './builtin.js';
export const g = makeTestGroup(GPUTest);
-const known_values = [-Math.sqrt(3), -1, -1 / Math.sqrt(3), 0, 1, 1 / Math.sqrt(3), Math.sqrt(3)];
-
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [...known_values, ...FP[trait].scalarRange()],
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].atanInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('atan', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/atan2.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/atan2.cache.ts
new file mode 100644
index 000000000000..b8174f647c7b
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/atan2.cache.ts
@@ -0,0 +1,27 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(kind =>
+ ([true, false] as const).map(nonConst => ({
+ [`${kind}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ // Using sparse range since there are N^2 cases being generated, and also including extra values
+ // around 0, where there is a discontinuity that implementations may behave badly at.
+ const numeric_range = [
+ ...FP[kind].sparseScalarRange(),
+ ...linearRange(FP[kind].constants().negative.max, FP[kind].constants().positive.min, 10),
+ ];
+ return FP[kind].generateScalarPairToIntervalCases(
+ numeric_range,
+ numeric_range,
+ nonConst ? 'unfiltered' : 'finite',
+ FP[kind].atan2Interval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('atan2', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/atan2.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/atan2.spec.ts
index 69eb08791e10..dff1d442f56b 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/atan2.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/atan2.spec.ts
@@ -9,40 +9,14 @@ Returns the arc tangent of e1 over e2. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
+import { d } from './atan2.cache.js';
import { builtin } from './builtin.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(kind =>
- ([true, false] as const).map(nonConst => ({
- [`${kind}_${nonConst ? 'non_const' : 'const'}`]: () => {
- // Using sparse range since there are N^2 cases being generated, and also including extra values
- // around 0, where there is a discontinuity that implementations may behave badly at.
- const numeric_range = [
- ...FP[kind].sparseScalarRange(),
- ...linearRange(FP[kind].constants().negative.max, FP[kind].constants().positive.min, 10),
- ];
- return FP[kind].generateScalarPairToIntervalCases(
- numeric_range,
- numeric_range,
- nonConst ? 'unfiltered' : 'finite',
- FP[kind].atan2Interval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('atan2', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/atanh.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/atanh.cache.ts
new file mode 100644
index 000000000000..b33fc4cdb8db
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/atanh.cache.ts
@@ -0,0 +1,28 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { biasedRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [
+ // discontinuity at x = -1
+ ...biasedRange(FP[trait].constants().negative.less_than_one, -0.9, 20),
+ -1,
+ // discontinuity at x = 1
+ ...biasedRange(FP[trait].constants().positive.less_than_one, 0.9, 20),
+ 1,
+ ...FP[trait].scalarRange(),
+ ],
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].atanhInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('atanh', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/atanh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/atanh.spec.ts
index e0b88f9efa96..31c14110b662 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/atanh.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/atanh.spec.ts
@@ -12,41 +12,14 @@ Note: The result is not mathematically meaningful when abs(e) >= 1.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { biasedRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
+import { d } from './atanh.cache.js';
import { builtin } from './builtin.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [
- // discontinuity at x = -1
- ...biasedRange(FP[trait].constants().negative.less_than_one, -0.9, 20),
- -1,
- // discontinuity at x = 1
- ...biasedRange(FP[trait].constants().positive.less_than_one, 0.9, 20),
- 1,
- ...FP[trait].scalarRange(),
- ],
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].atanhInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('atanh', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/bitcast.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/bitcast.cache.ts
new file mode 100644
index 000000000000..60fbc2b03ec8
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/bitcast.cache.ts
@@ -0,0 +1,797 @@
+import { assert } from '../../../../../../common/util/util.js';
+import { Comparator, alwaysPass, anyOf } from '../../../../../util/compare.js';
+import { kBit, kValue } from '../../../../../util/constants.js';
+import { Scalar, Vector, f16, f32, i32, toVector, u32 } from '../../../../../util/conversion.js';
+import { FP, FPInterval } from '../../../../../util/floating_point.js';
+import {
+ cartesianProduct,
+ fullI32Range,
+ fullU32Range,
+ isFiniteF16,
+ isFiniteF32,
+ isSubnormalNumberF16,
+ isSubnormalNumberF32,
+ linearRange,
+ scalarF16Range,
+ scalarF32Range,
+} from '../../../../../util/math.js';
+import {
+ reinterpretF16AsU16,
+ reinterpretF32AsI32,
+ reinterpretF32AsU32,
+ reinterpretI32AsF32,
+ reinterpretI32AsU32,
+ reinterpretU16AsF16,
+ reinterpretU32AsF32,
+ reinterpretU32AsI32,
+} from '../../../../../util/reinterpret.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+const numNaNs = 11;
+const f32InfAndNaNInU32: number[] = [
+ // Cover NaNs evenly in integer space.
+ // The positive NaN with the lowest integer representation is the integer
+ // for infinity, plus one.
+ // The positive NaN with the highest integer representation is i32.max (!)
+ ...linearRange(kBit.f32.positive.infinity + 1, kBit.i32.positive.max, numNaNs),
+ // The negative NaN with the lowest integer representation is the integer
+ // for negative infinity, plus one.
+ // The negative NaN with the highest integer representation is u32.max (!)
+ ...linearRange(kBit.f32.negative.infinity + 1, kBit.u32.max, numNaNs),
+ kBit.f32.positive.infinity,
+ kBit.f32.negative.infinity,
+];
+const f32InfAndNaNInF32 = f32InfAndNaNInU32.map(u => reinterpretU32AsF32(u));
+const f32InfAndNaNInI32 = f32InfAndNaNInU32.map(u => reinterpretU32AsI32(u));
+
+const f32ZerosInU32 = [0, kBit.f32.negative.zero];
+const f32ZerosInF32 = f32ZerosInU32.map(u => reinterpretU32AsF32(u));
+const f32ZerosInI32 = f32ZerosInU32.map(u => reinterpretU32AsI32(u));
+const f32ZerosInterval: FPInterval = new FPInterval('f32', -0.0, 0.0);
+
+// f32FiniteRange is a list of finite f32s. fullF32Range() already
+// has +0, we only need to add -0.
+const f32FiniteRange: number[] = [...scalarF32Range(), kValue.f32.negative.zero];
+const f32RangeWithInfAndNaN: number[] = [...f32FiniteRange, ...f32InfAndNaNInF32];
+
+// F16 values, finite, Inf/NaN, and zeros. Represented in float and u16.
+const f16FiniteInF16: number[] = [...scalarF16Range(), kValue.f16.negative.zero];
+const f16FiniteInU16: number[] = f16FiniteInF16.map(u => reinterpretF16AsU16(u));
+
+const f16InfAndNaNInU16: number[] = [
+ // Cover NaNs evenly in integer space.
+ // The positive NaN with the lowest integer representation is the integer
+ // for infinity, plus one.
+ // The positive NaN with the highest integer representation is u16 0x7fff i.e. 32767.
+ ...linearRange(kBit.f16.positive.infinity + 1, 32767, numNaNs).map(v => Math.ceil(v)),
+ // The negative NaN with the lowest integer representation is the integer
+ // for negative infinity, plus one.
+ // The negative NaN with the highest integer representation is u16 0xffff i.e. 65535
+ ...linearRange(kBit.f16.negative.infinity + 1, 65535, numNaNs).map(v => Math.floor(v)),
+ kBit.f16.positive.infinity,
+ kBit.f16.negative.infinity,
+];
+const f16InfAndNaNInF16 = f16InfAndNaNInU16.map(u => reinterpretU16AsF16(u));
+
+const f16ZerosInU16 = [kBit.f16.negative.zero, 0];
+
+// f16 interval that match +/-0.0.
+const f16ZerosInterval: FPInterval = new FPInterval('f16', -0.0, 0.0);
+
+/**
+ * @returns an u32 whose lower and higher 16bits are the two elements of the
+ * given array of two u16 respectively, in little-endian.
+ */
+function u16x2ToU32(u16x2: readonly number[]): number {
+ assert(u16x2.length === 2);
+ // Create a DataView with 4 bytes buffer.
+ const buffer = new ArrayBuffer(4);
+ const view = new DataView(buffer);
+ // Enforce little-endian.
+ view.setUint16(0, u16x2[0], true);
+ view.setUint16(2, u16x2[1], true);
+ return view.getUint32(0, true);
+}
+
+/**
+ * @returns an array of two u16, respectively the lower and higher 16bits of
+ * given u32 in little-endian.
+ */
+function u32ToU16x2(u32: number): number[] {
+ // Create a DataView with 4 bytes buffer.
+ const buffer = new ArrayBuffer(4);
+ const view = new DataView(buffer);
+ // Enforce little-endian.
+ view.setUint32(0, u32, true);
+ return [view.getUint16(0, true), view.getUint16(2, true)];
+}
+
+/**
+ * @returns a vec2 from an array of two u16, each reinterpreted as f16.
+ */
+function u16x2ToVec2F16(u16x2: number[]): Vector {
+ assert(u16x2.length === 2);
+ return toVector(u16x2.map(reinterpretU16AsF16), f16);
+}
+
+/**
+ * @returns a vec4 from an array of four u16, each reinterpreted as f16.
+ */
+function u16x4ToVec4F16(u16x4: number[]): Vector {
+ assert(u16x4.length === 4);
+ return toVector(u16x4.map(reinterpretU16AsF16), f16);
+}
+
+/**
+ * @returns true if and only if a given u32 can bitcast to a vec2 with all elements
+ * being finite f16 values.
+ */
+function canU32BitcastToFiniteVec2F16(u32: number): boolean {
+ return u32ToU16x2(u32)
+ .map(u16 => isFiniteF16(reinterpretU16AsF16(u16)))
+ .reduce((a, b) => a && b, true);
+}
+
+/**
+ * @returns an array of N elements with the i-th element being an array of len elements
+ * [a_i, a_((i+1)%N), ..., a_((i+len-1)%N)], for the input array of N element [a_1, ... a_N]
+ * and the given len. For example, slidingSlice([1, 2, 3], 2) result in
+ * [[1, 2], [2, 3], [3, 1]].
+ * This helper function is used for generating vector cases from scalar values array.
+ */
+function slidingSlice(input: number[], len: number) {
+ const result: number[][] = [];
+ for (let i = 0; i < input.length; i++) {
+ const sub: number[] = [];
+ for (let j = 0; j < len; j++) {
+ sub.push(input[(i + j) % input.length]);
+ }
+ result.push(sub);
+ }
+ return result;
+}
+
+// vec2 interesting (zeros, Inf, and NaN) values for testing cases.
+// vec2 values that has at least one Inf/NaN f16 element, reinterpreted as u32/i32.
+const f16Vec2InfAndNaNInU32 = [
+ ...cartesianProduct(f16InfAndNaNInU16, [...f16InfAndNaNInU16, ...f16FiniteInU16]),
+ ...cartesianProduct(f16FiniteInU16, f16InfAndNaNInU16),
+].map(u16x2ToU32);
+const f16Vec2InfAndNaNInI32 = f16Vec2InfAndNaNInU32.map(u => reinterpretU32AsI32(u));
+// vec2 values with two f16 0.0 element, reinterpreted as u32/i32.
+const f16Vec2ZerosInU32 = cartesianProduct(f16ZerosInU16, f16ZerosInU16).map(u16x2ToU32);
+const f16Vec2ZerosInI32 = f16Vec2ZerosInU32.map(u => reinterpretU32AsI32(u));
+
+// i32/u32/f32 range for bitcasting to vec2
+// u32 values for bitcasting to vec2 finite, Inf, and NaN.
+const u32RangeForF16Vec2FiniteInfNaN: number[] = [
+ ...fullU32Range(),
+ ...f16Vec2ZerosInU32,
+ ...f16Vec2InfAndNaNInU32,
+];
+// u32 values for bitcasting to finite only vec2, used for constant evaluation.
+const u32RangeForF16Vec2Finite: number[] = u32RangeForF16Vec2FiniteInfNaN.filter(
+ canU32BitcastToFiniteVec2F16
+);
+// i32 values for bitcasting to vec2 finite, zeros, Inf, and NaN.
+const i32RangeForF16Vec2FiniteInfNaN: number[] = [
+ ...fullI32Range(),
+ ...f16Vec2ZerosInI32,
+ ...f16Vec2InfAndNaNInI32,
+];
+// i32 values for bitcasting to finite only vec2, used for constant evaluation.
+const i32RangeForF16Vec2Finite: number[] = i32RangeForF16Vec2FiniteInfNaN.filter(u =>
+ canU32BitcastToFiniteVec2F16(reinterpretI32AsU32(u))
+);
+// f32 values with finite/Inf/NaN f32, for bitcasting to vec2 finite, zeros, Inf, and NaN.
+const f32RangeWithInfAndNaNForF16Vec2FiniteInfNaN: number[] = [
+ ...f32RangeWithInfAndNaN,
+ ...u32RangeForF16Vec2FiniteInfNaN.map(reinterpretU32AsF32),
+];
+// Finite f32 values for bitcasting to finite only vec2, used for constant evaluation.
+const f32FiniteRangeForF16Vec2Finite: number[] = f32RangeWithInfAndNaNForF16Vec2FiniteInfNaN
+ .filter(isFiniteF32)
+ .filter(u => canU32BitcastToFiniteVec2F16(reinterpretF32AsU32(u)));
+
+// vec2 cases for bitcasting to i32/u32/f32, by combining f16 values into pairs
+const f16Vec2FiniteInU16x2 = slidingSlice(f16FiniteInU16, 2);
+const f16Vec2FiniteInfNanInU16x2 = slidingSlice([...f16FiniteInU16, ...f16InfAndNaNInU16], 2);
+// vec4 cases for bitcasting to vec2, by combining f16 values 4-by-4
+const f16Vec2FiniteInU16x4 = slidingSlice(f16FiniteInU16, 4);
+const f16Vec2FiniteInfNanInU16x4 = slidingSlice([...f16FiniteInU16, ...f16InfAndNaNInU16], 4);
+
+// alwaysPass comparator for i32/u32/f32 cases. For f32/f16 we also use unbound interval, which
+// allow per-element unbounded expectation for vector.
+const anyF32 = alwaysPass('any f32');
+const anyI32 = alwaysPass('any i32');
+const anyU32 = alwaysPass('any u32');
+
+// Unbounded FPInterval
+const f32UnboundedInterval = FP.f32.constants().unboundedInterval;
+const f16UnboundedInterval = FP.f16.constants().unboundedInterval;
+
+// i32 and u32 cases for bitcasting to f32.
+// i32 cases for bitcasting to f32 finite, zeros, Inf, and NaN.
+const i32RangeForF32FiniteInfNaN: number[] = [
+ ...fullI32Range(),
+ ...f32ZerosInI32,
+ ...f32InfAndNaNInI32,
+];
+// i32 cases for bitcasting to f32 finite only.
+const i32RangeForF32Finite: number[] = i32RangeForF32FiniteInfNaN.filter(i =>
+ isFiniteF32(reinterpretI32AsF32(i))
+);
+// u32 cases for bitcasting to f32 finite, zeros, Inf, and NaN.
+const u32RangeForF32FiniteInfNaN: number[] = [
+ ...fullU32Range(),
+ ...f32ZerosInU32,
+ ...f32InfAndNaNInU32,
+];
+// u32 cases for bitcasting to f32 finite only.
+const u32RangeForF32Finite: number[] = u32RangeForF32FiniteInfNaN.filter(u =>
+ isFiniteF32(reinterpretU32AsF32(u))
+);
+
+/**
+ * @returns a Comparator for checking if a f32 value is a valid
+ * bitcast conversion from f32.
+ */
+function bitcastF32ToF32Comparator(f: number): Comparator {
+ if (!isFiniteF32(f)) return anyF32;
+ const acceptable: number[] = [f, ...(isSubnormalNumberF32(f) ? f32ZerosInF32 : [])];
+ return anyOf(...acceptable.map(f32));
+}
+
+/**
+ * @returns a Comparator for checking if a u32 value is a valid
+ * bitcast conversion from f32.
+ */
+function bitcastF32ToU32Comparator(f: number): Comparator {
+ if (!isFiniteF32(f)) return anyU32;
+ const acceptable: number[] = [
+ reinterpretF32AsU32(f),
+ ...(isSubnormalNumberF32(f) ? f32ZerosInU32 : []),
+ ];
+ return anyOf(...acceptable.map(u32));
+}
+
+/**
+ * @returns a Comparator for checking if a i32 value is a valid
+ * bitcast conversion from f32.
+ */
+function bitcastF32ToI32Comparator(f: number): Comparator {
+ if (!isFiniteF32(f)) return anyI32;
+ const acceptable: number[] = [
+ reinterpretF32AsI32(f),
+ ...(isSubnormalNumberF32(f) ? f32ZerosInI32 : []),
+ ];
+ return anyOf(...acceptable.map(i32));
+}
+
+/**
+ * @returns a Comparator for checking if a f32 value is a valid
+ * bitcast conversion from i32.
+ */
+function bitcastI32ToF32Comparator(i: number): Comparator {
+ const f: number = reinterpretI32AsF32(i);
+ if (!isFiniteF32(f)) return anyI32;
+ // Positive or negative zero bit pattern map to any zero.
+ if (f32ZerosInI32.includes(i)) return anyOf(...f32ZerosInF32.map(f32));
+ const acceptable: number[] = [f, ...(isSubnormalNumberF32(f) ? f32ZerosInF32 : [])];
+ return anyOf(...acceptable.map(f32));
+}
+
+/**
+ * @returns a Comparator for checking if a f32 value is a valid
+ * bitcast conversion from u32.
+ */
+function bitcastU32ToF32Comparator(u: number): Comparator {
+ const f: number = reinterpretU32AsF32(u);
+ if (!isFiniteF32(f)) return anyU32;
+ // Positive or negative zero bit pattern map to any zero.
+ if (f32ZerosInU32.includes(u)) return anyOf(...f32ZerosInF32.map(f32));
+ const acceptable: number[] = [f, ...(isSubnormalNumberF32(f) ? f32ZerosInF32 : [])];
+ return anyOf(...acceptable.map(f32));
+}
+
+/**
+ * @returns an array of expected f16 FPInterval for the given bitcasted f16 value, which may be
+ * subnormal, Inf, or NaN. Test cases that bitcasted to vector of f16 use this function to get
+ * per-element expectation and build vector expectation using cartesianProduct.
+ */
+function generateF16ExpectationIntervals(bitcastedF16Value: number): FPInterval[] {
+ // If the bitcasted f16 value is inf or nan, the result is unbounded
+ if (!isFiniteF16(bitcastedF16Value)) {
+ return [f16UnboundedInterval];
+ }
+ // If the casted f16 value is +/-0.0, the result can be one of both. Note that in JS -0.0 === 0.0.
+ if (bitcastedF16Value === 0.0) {
+ return [f16ZerosInterval];
+ }
+ const exactInterval = FP.f16.toInterval(bitcastedF16Value);
+ // If the casted f16 value is subnormal, it also may be flushed to +/-0.0.
+ return [exactInterval, ...(isSubnormalNumberF16(bitcastedF16Value) ? [f16ZerosInterval] : [])];
+}
+
+/**
+ * @returns a Comparator for checking if a f16 value is a valid
+ * bitcast conversion from f16.
+ */
+function bitcastF16ToF16Comparator(f: number): Comparator {
+ if (!isFiniteF16(f)) return anyOf(f16UnboundedInterval);
+ return anyOf(...generateF16ExpectationIntervals(f));
+}
+
+/**
+ * @returns a Comparator for checking if a vec2 is a valid bitcast
+ * conversion from u32.
+ */
+function bitcastU32ToVec2F16Comparator(u: number): Comparator {
+ const bitcastedVec2F16InU16x2 = u32ToU16x2(u).map(reinterpretU16AsF16);
+ // Generate expection for vec2 f16 result, by generating expected intervals for each elements and
+ // then do cartesian product.
+ const expectedIntervalsCombination = cartesianProduct(
+ ...bitcastedVec2F16InU16x2.map(generateF16ExpectationIntervals)
+ );
+ return anyOf(...expectedIntervalsCombination);
+}
+
+/**
+ * @returns a Comparator for checking if a vec2 value is a valid
+ * bitcast conversion from i32.
+ */
+function bitcastI32ToVec2F16Comparator(i: number): Comparator {
+ const bitcastedVec2F16InU16x2 = u32ToU16x2(reinterpretI32AsU32(i)).map(reinterpretU16AsF16);
+ // Generate expection for vec2 f16 result, by generating expected intervals for each elements and
+ // then do cartesian product.
+ const expectedIntervalsCombination = cartesianProduct(
+ ...bitcastedVec2F16InU16x2.map(generateF16ExpectationIntervals)
+ );
+ return anyOf(...expectedIntervalsCombination);
+}
+
+/**
+ * @returns a Comparator for checking if a vec2 value is a valid
+ * bitcast conversion from f32.
+ */
+function bitcastF32ToVec2F16Comparator(f: number): Comparator {
+ // If input f32 is not finite, it can be evaluated to any value and thus any result f16 vec2 is
+ // possible.
+ if (!isFiniteF32(f)) {
+ return anyOf([f16UnboundedInterval, f16UnboundedInterval]);
+ }
+ const bitcastedVec2F16InU16x2 = u32ToU16x2(reinterpretF32AsU32(f)).map(reinterpretU16AsF16);
+ // Generate expection for vec2 f16 result, by generating expected intervals for each elements and
+ // then do cartesian product.
+ const expectedIntervalsCombination = cartesianProduct(
+ ...bitcastedVec2F16InU16x2.map(generateF16ExpectationIntervals)
+ );
+ return anyOf(...expectedIntervalsCombination);
+}
+
+/**
+ * @returns a Comparator for checking if a vec4 is a valid
+ * bitcast conversion from vec2.
+ */
+function bitcastVec2U32ToVec4F16Comparator(u32x2: number[]): Comparator {
+ assert(u32x2.length === 2);
+ const bitcastedVec4F16InU16x4 = u32x2.flatMap(u32ToU16x2).map(reinterpretU16AsF16);
+ // Generate expection for vec4 f16 result, by generating expected intervals for each elements and
+ // then do cartesian product.
+ const expectedIntervalsCombination = cartesianProduct(
+ ...bitcastedVec4F16InU16x4.map(generateF16ExpectationIntervals)
+ );
+ return anyOf(...expectedIntervalsCombination);
+}
+
+/**
+ * @returns a Comparator for checking if a vec4 is a valid
+ * bitcast conversion from vec2.
+ */
+function bitcastVec2I32ToVec4F16Comparator(i32x2: number[]): Comparator {
+ assert(i32x2.length === 2);
+ const bitcastedVec4F16InU16x4 = i32x2
+ .map(reinterpretI32AsU32)
+ .flatMap(u32ToU16x2)
+ .map(reinterpretU16AsF16);
+ // Generate expection for vec4 f16 result, by generating expected intervals for each elements and
+ // then do cartesian product.
+ const expectedIntervalsCombination = cartesianProduct(
+ ...bitcastedVec4F16InU16x4.map(generateF16ExpectationIntervals)
+ );
+ return anyOf(...expectedIntervalsCombination);
+}
+
+/**
+ * @returns a Comparator for checking if a vec4 is a valid
+ * bitcast conversion from vec2.
+ */
+function bitcastVec2F32ToVec4F16Comparator(f32x2: number[]): Comparator {
+ assert(f32x2.length === 2);
+ const bitcastedVec4F16InU16x4 = f32x2
+ .map(reinterpretF32AsU32)
+ .flatMap(u32ToU16x2)
+ .map(reinterpretU16AsF16);
+ // Generate expection for vec4 f16 result, by generating expected intervals for each elements and
+ // then do cartesian product.
+ const expectedIntervalsCombination = cartesianProduct(
+ ...bitcastedVec4F16InU16x4.map(generateF16ExpectationIntervals)
+ );
+ return anyOf(...expectedIntervalsCombination);
+}
+
+// Structure that store the expectations of a single 32bit scalar/element bitcasted from two f16.
+interface ExpectionFor32BitsScalarFromF16x2 {
+ // possibleExpectations is Scalar array if the expectation is for i32/u32 and FPInterval array for
+ // f32. Note that if the expectation for i32/u32 is unbound, possibleExpectations is meaningless.
+ possibleExpectations: (Scalar | FPInterval)[];
+ isUnbounded: boolean;
+}
+
+/**
+ * @returns the array of possible 16bits, represented in u16, that bitcasted
+ * from a given finite f16 represented in u16, handling the possible subnormal
+ * flushing. Used to build up 32bits or larger results.
+ */
+function possibleBitsInU16FromFiniteF16InU16(f16InU16: number): number[] {
+ const h = reinterpretU16AsF16(f16InU16);
+ assert(isFiniteF16(h));
+ return [f16InU16, ...(isSubnormalNumberF16(h) ? f16ZerosInU16 : [])];
+}
+
+/**
+ * @returns the expectation for a single 32bit scalar bitcasted from given pair of
+ * f16, result in ExpectionFor32BitsScalarFromF16x2.
+ */
+function possible32BitScalarIntervalsFromF16x2(
+ f16x2InU16x2: number[],
+ type: 'i32' | 'u32' | 'f32'
+): ExpectionFor32BitsScalarFromF16x2 {
+ assert(f16x2InU16x2.length === 2);
+ let reinterpretFromU32: (x: number) => number;
+ let expectationsForValue: (x: number) => Scalar[] | FPInterval[];
+ let unboundedExpectations: FPInterval[] | Scalar[];
+ if (type === 'u32') {
+ reinterpretFromU32 = (x: number) => x;
+ expectationsForValue = x => [u32(x)];
+ // Scalar expectation can not express "unbounded" for i32 and u32, so use 0 here as a
+ // placeholder, and the possibleExpectations should be ignored if the result is unbounded.
+ unboundedExpectations = [u32(0)];
+ } else if (type === 'i32') {
+ reinterpretFromU32 = (x: number) => reinterpretU32AsI32(x);
+ expectationsForValue = x => [i32(x)];
+ // Scalar expectation can not express "unbounded" for i32 and u32, so use 0 here as a
+ // placeholder, and the possibleExpectations should be ignored if the result is unbounded.
+ unboundedExpectations = [i32(0)];
+ } else {
+ assert(type === 'f32');
+ reinterpretFromU32 = (x: number) => reinterpretU32AsF32(x);
+ expectationsForValue = x => {
+ // Handle the possible Inf/NaN/zeros and subnormal cases for f32 result.
+ if (!isFiniteF32(x)) {
+ return [f32UnboundedInterval];
+ }
+ // If the casted f16 value is +/-0.0, the result can be one of both. Note that in JS -0.0 === 0.0.
+ if (x === 0.0) {
+ return [f32ZerosInterval];
+ }
+ const exactInterval = FP.f32.toInterval(x);
+ // If the casted f16 value is subnormal, it also may be flushed to +/-0.0.
+ return [exactInterval, ...(isSubnormalNumberF32(x) ? [f32ZerosInterval] : [])];
+ };
+ unboundedExpectations = [f32UnboundedInterval];
+ }
+ // Return unbounded expection if f16 Inf/NaN occurs
+ if (
+ !isFiniteF16(reinterpretU16AsF16(f16x2InU16x2[0])) ||
+ !isFiniteF16(reinterpretU16AsF16(f16x2InU16x2[1]))
+ ) {
+ return { possibleExpectations: unboundedExpectations, isUnbounded: true };
+ }
+ const possibleU16Bits = f16x2InU16x2.map(possibleBitsInU16FromFiniteF16InU16);
+ const possibleExpectations = cartesianProduct(...possibleU16Bits).flatMap(
+ (possibleBitsU16x2: readonly number[]) => {
+ assert(possibleBitsU16x2.length === 2);
+ return expectationsForValue(reinterpretFromU32(u16x2ToU32(possibleBitsU16x2)));
+ }
+ );
+ return { possibleExpectations, isUnbounded: false };
+}
+
+/**
+ * @returns a Comparator for checking if a u32 value is a valid
+ * bitcast conversion from vec2 f16.
+ */
+function bitcastVec2F16ToU32Comparator(vec2F16InU16x2: number[]): Comparator {
+ assert(vec2F16InU16x2.length === 2);
+ const expectations = possible32BitScalarIntervalsFromF16x2(vec2F16InU16x2, 'u32');
+ // Return alwaysPass if result is expected unbounded.
+ if (expectations.isUnbounded) {
+ return anyU32;
+ }
+ return anyOf(...expectations.possibleExpectations);
+}
+
+/**
+ * @returns a Comparator for checking if a i32 value is a valid
+ * bitcast conversion from vec2 f16.
+ */
+function bitcastVec2F16ToI32Comparator(vec2F16InU16x2: number[]): Comparator {
+ assert(vec2F16InU16x2.length === 2);
+ const expectations = possible32BitScalarIntervalsFromF16x2(vec2F16InU16x2, 'i32');
+ // Return alwaysPass if result is expected unbounded.
+ if (expectations.isUnbounded) {
+ return anyI32;
+ }
+ return anyOf(...expectations.possibleExpectations);
+}
+
+/**
+ * @returns a Comparator for checking if a i32 value is a valid
+ * bitcast conversion from vec2 f16.
+ */
+function bitcastVec2F16ToF32Comparator(vec2F16InU16x2: number[]): Comparator {
+ assert(vec2F16InU16x2.length === 2);
+ const expectations = possible32BitScalarIntervalsFromF16x2(vec2F16InU16x2, 'f32');
+ // Return alwaysPass if result is expected unbounded.
+ if (expectations.isUnbounded) {
+ return anyF32;
+ }
+ return anyOf(...expectations.possibleExpectations);
+}
+
+/**
+ * @returns a Comparator for checking if a vec2 u32 value is a valid
+ * bitcast conversion from vec4 f16.
+ */
+function bitcastVec4F16ToVec2U32Comparator(vec4F16InU16x4: number[]): Comparator {
+ assert(vec4F16InU16x4.length === 4);
+ const expectationsPerElement = [vec4F16InU16x4.slice(0, 2), vec4F16InU16x4.slice(2, 4)].map(e =>
+ possible32BitScalarIntervalsFromF16x2(e, 'u32')
+ );
+ // Return alwaysPass if any element is expected unbounded. Although it may be only one unbounded
+ // element in the result vector, currently we don't have a way to build a comparator that expect
+ // only one element of i32/u32 vector unbounded.
+ if (expectationsPerElement.map(e => e.isUnbounded).reduce((a, b) => a || b, false)) {
+ return alwaysPass('any vec2');
+ }
+ return anyOf(
+ ...cartesianProduct(...expectationsPerElement.map(e => e.possibleExpectations)).map(
+ e => new Vector(e as Scalar[])
+ )
+ );
+}
+
+/**
+ * @returns a Comparator for checking if a vec2 i32 value is a valid
+ * bitcast conversion from vec4 f16.
+ */
+function bitcastVec4F16ToVec2I32Comparator(vec4F16InU16x4: number[]): Comparator {
+ assert(vec4F16InU16x4.length === 4);
+ const expectationsPerElement = [vec4F16InU16x4.slice(0, 2), vec4F16InU16x4.slice(2, 4)].map(e =>
+ possible32BitScalarIntervalsFromF16x2(e, 'i32')
+ );
+ // Return alwaysPass if any element is expected unbounded. Although it may be only one unbounded
+ // element in the result vector, currently we don't have a way to build a comparator that expect
+ // only one element of i32/u32 vector unbounded.
+ if (expectationsPerElement.map(e => e.isUnbounded).reduce((a, b) => a || b, false)) {
+ return alwaysPass('any vec2');
+ }
+ return anyOf(
+ ...cartesianProduct(...expectationsPerElement.map(e => e.possibleExpectations)).map(
+ e => new Vector(e as Scalar[])
+ )
+ );
+}
+
+/**
+ * @returns a Comparator for checking if a vec2 f32 value is a valid
+ * bitcast conversion from vec4 f16.
+ */
+function bitcastVec4F16ToVec2F32Comparator(vec4F16InU16x4: number[]): Comparator {
+ assert(vec4F16InU16x4.length === 4);
+ const expectationsPerElement = [vec4F16InU16x4.slice(0, 2), vec4F16InU16x4.slice(2, 4)].map(e =>
+ possible32BitScalarIntervalsFromF16x2(e, 'f32')
+ );
+ return anyOf(
+ ...cartesianProduct(...expectationsPerElement.map(e => e.possibleExpectations)).map(e => [
+ e[0] as FPInterval,
+ e[1] as FPInterval,
+ ])
+ );
+}
+
+export const d = makeCaseCache('bitcast', {
+ // Identity Cases
+ i32_to_i32: () => fullI32Range().map(e => ({ input: i32(e), expected: i32(e) })),
+ u32_to_u32: () => fullU32Range().map(e => ({ input: u32(e), expected: u32(e) })),
+ f32_inf_nan_to_f32: () =>
+ f32RangeWithInfAndNaN.map(e => ({
+ input: f32(e),
+ expected: bitcastF32ToF32Comparator(e),
+ })),
+ f32_to_f32: () =>
+ f32FiniteRange.map(e => ({ input: f32(e), expected: bitcastF32ToF32Comparator(e) })),
+ f16_inf_nan_to_f16: () =>
+ [...f16FiniteInF16, ...f16InfAndNaNInF16].map(e => ({
+ input: f16(e),
+ expected: bitcastF16ToF16Comparator(e),
+ })),
+ f16_to_f16: () =>
+ f16FiniteInF16.map(e => ({ input: f16(e), expected: bitcastF16ToF16Comparator(e) })),
+
+ // i32,u32,f32 to different i32,u32,f32
+ i32_to_u32: () => fullI32Range().map(e => ({ input: i32(e), expected: u32(e) })),
+ i32_to_f32: () =>
+ i32RangeForF32Finite.map(e => ({
+ input: i32(e),
+ expected: bitcastI32ToF32Comparator(e),
+ })),
+ i32_to_f32_inf_nan: () =>
+ i32RangeForF32FiniteInfNaN.map(e => ({
+ input: i32(e),
+ expected: bitcastI32ToF32Comparator(e),
+ })),
+ u32_to_i32: () => fullU32Range().map(e => ({ input: u32(e), expected: i32(e) })),
+ u32_to_f32: () =>
+ u32RangeForF32Finite.map(e => ({
+ input: u32(e),
+ expected: bitcastU32ToF32Comparator(e),
+ })),
+ u32_to_f32_inf_nan: () =>
+ u32RangeForF32FiniteInfNaN.map(e => ({
+ input: u32(e),
+ expected: bitcastU32ToF32Comparator(e),
+ })),
+ f32_inf_nan_to_i32: () =>
+ f32RangeWithInfAndNaN.map(e => ({
+ input: f32(e),
+ expected: bitcastF32ToI32Comparator(e),
+ })),
+ f32_to_i32: () =>
+ f32FiniteRange.map(e => ({ input: f32(e), expected: bitcastF32ToI32Comparator(e) })),
+
+ f32_inf_nan_to_u32: () =>
+ f32RangeWithInfAndNaN.map(e => ({
+ input: f32(e),
+ expected: bitcastF32ToU32Comparator(e),
+ })),
+ f32_to_u32: () =>
+ f32FiniteRange.map(e => ({ input: f32(e), expected: bitcastF32ToU32Comparator(e) })),
+
+ // i32,u32,f32 to vec2
+ u32_to_vec2_f16_inf_nan: () =>
+ u32RangeForF16Vec2FiniteInfNaN.map(e => ({
+ input: u32(e),
+ expected: bitcastU32ToVec2F16Comparator(e),
+ })),
+ u32_to_vec2_f16: () =>
+ u32RangeForF16Vec2Finite.map(e => ({
+ input: u32(e),
+ expected: bitcastU32ToVec2F16Comparator(e),
+ })),
+ i32_to_vec2_f16_inf_nan: () =>
+ i32RangeForF16Vec2FiniteInfNaN.map(e => ({
+ input: i32(e),
+ expected: bitcastI32ToVec2F16Comparator(e),
+ })),
+ i32_to_vec2_f16: () =>
+ i32RangeForF16Vec2Finite.map(e => ({
+ input: i32(e),
+ expected: bitcastI32ToVec2F16Comparator(e),
+ })),
+ f32_inf_nan_to_vec2_f16_inf_nan: () =>
+ f32RangeWithInfAndNaNForF16Vec2FiniteInfNaN.map(e => ({
+ input: f32(e),
+ expected: bitcastF32ToVec2F16Comparator(e),
+ })),
+ f32_to_vec2_f16: () =>
+ f32FiniteRangeForF16Vec2Finite.map(e => ({
+ input: f32(e),
+ expected: bitcastF32ToVec2F16Comparator(e),
+ })),
+
+ // vec2, vec2, vec2 to vec4
+ vec2_i32_to_vec4_f16_inf_nan: () =>
+ slidingSlice(i32RangeForF16Vec2FiniteInfNaN, 2).map(e => ({
+ input: toVector(e, i32),
+ expected: bitcastVec2I32ToVec4F16Comparator(e),
+ })),
+ vec2_i32_to_vec4_f16: () =>
+ slidingSlice(i32RangeForF16Vec2Finite, 2).map(e => ({
+ input: toVector(e, i32),
+ expected: bitcastVec2I32ToVec4F16Comparator(e),
+ })),
+ vec2_u32_to_vec4_f16_inf_nan: () =>
+ slidingSlice(u32RangeForF16Vec2FiniteInfNaN, 2).map(e => ({
+ input: toVector(e, u32),
+ expected: bitcastVec2U32ToVec4F16Comparator(e),
+ })),
+ vec2_u32_to_vec4_f16: () =>
+ slidingSlice(u32RangeForF16Vec2Finite, 2).map(e => ({
+ input: toVector(e, u32),
+ expected: bitcastVec2U32ToVec4F16Comparator(e),
+ })),
+ vec2_f32_inf_nan_to_vec4_f16_inf_nan: () =>
+ slidingSlice(f32RangeWithInfAndNaNForF16Vec2FiniteInfNaN, 2).map(e => ({
+ input: toVector(e, f32),
+ expected: bitcastVec2F32ToVec4F16Comparator(e),
+ })),
+ vec2_f32_to_vec4_f16: () =>
+ slidingSlice(f32FiniteRangeForF16Vec2Finite, 2).map(e => ({
+ input: toVector(e, f32),
+ expected: bitcastVec2F32ToVec4F16Comparator(e),
+ })),
+
+ // vec2 to i32, u32, f32
+ vec2_f16_to_u32: () =>
+ f16Vec2FiniteInU16x2.map(e => ({
+ input: u16x2ToVec2F16(e),
+ expected: bitcastVec2F16ToU32Comparator(e),
+ })),
+ vec2_f16_inf_nan_to_u32: () =>
+ f16Vec2FiniteInfNanInU16x2.map(e => ({
+ input: u16x2ToVec2F16(e),
+ expected: bitcastVec2F16ToU32Comparator(e),
+ })),
+ vec2_f16_to_i32: () =>
+ f16Vec2FiniteInU16x2.map(e => ({
+ input: u16x2ToVec2F16(e),
+ expected: bitcastVec2F16ToI32Comparator(e),
+ })),
+ vec2_f16_inf_nan_to_i32: () =>
+ f16Vec2FiniteInfNanInU16x2.map(e => ({
+ input: u16x2ToVec2F16(e),
+ expected: bitcastVec2F16ToI32Comparator(e),
+ })),
+ vec2_f16_to_f32_finite: () =>
+ f16Vec2FiniteInU16x2
+ .filter(u16x2 => isFiniteF32(reinterpretU32AsF32(u16x2ToU32(u16x2))))
+ .map(e => ({
+ input: u16x2ToVec2F16(e),
+ expected: bitcastVec2F16ToF32Comparator(e),
+ })),
+ vec2_f16_inf_nan_to_f32: () =>
+ f16Vec2FiniteInfNanInU16x2.map(e => ({
+ input: u16x2ToVec2F16(e),
+ expected: bitcastVec2F16ToF32Comparator(e),
+ })),
+
+ // vec4 to vec2 of i32, u32, f32
+ vec4_f16_to_vec2_u32: () =>
+ f16Vec2FiniteInU16x4.map(e => ({
+ input: u16x4ToVec4F16(e),
+ expected: bitcastVec4F16ToVec2U32Comparator(e),
+ })),
+ vec4_f16_inf_nan_to_vec2_u32: () =>
+ f16Vec2FiniteInfNanInU16x4.map(e => ({
+ input: u16x4ToVec4F16(e),
+ expected: bitcastVec4F16ToVec2U32Comparator(e),
+ })),
+ vec4_f16_to_vec2_i32: () =>
+ f16Vec2FiniteInU16x4.map(e => ({
+ input: u16x4ToVec4F16(e),
+ expected: bitcastVec4F16ToVec2I32Comparator(e),
+ })),
+ vec4_f16_inf_nan_to_vec2_i32: () =>
+ f16Vec2FiniteInfNanInU16x4.map(e => ({
+ input: u16x4ToVec4F16(e),
+ expected: bitcastVec4F16ToVec2I32Comparator(e),
+ })),
+ vec4_f16_to_vec2_f32_finite: () =>
+ f16Vec2FiniteInU16x4
+ .filter(
+ u16x4 =>
+ isFiniteF32(reinterpretU32AsF32(u16x2ToU32(u16x4.slice(0, 2)))) &&
+ isFiniteF32(reinterpretU32AsF32(u16x2ToU32(u16x4.slice(2, 4))))
+ )
+ .map(e => ({
+ input: u16x4ToVec4F16(e),
+ expected: bitcastVec4F16ToVec2F32Comparator(e),
+ })),
+ vec4_f16_inf_nan_to_vec2_f32: () =>
+ f16Vec2FiniteInfNanInU16x4.map(e => ({
+ input: u16x4ToVec4F16(e),
+ expected: bitcastVec4F16ToVec2F32Comparator(e),
+ })),
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/bitcast.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/bitcast.spec.ts
index 13663a28409f..32d32a27ad43 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/bitcast.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/bitcast.spec.ts
@@ -20,823 +20,15 @@ T is i32, u32, f32
import { TestParams } from '../../../../../../common/framework/fixture.js';
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
-import { assert } from '../../../../../../common/util/util.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { Comparator, alwaysPass, anyOf } from '../../../../../util/compare.js';
-import { kBit, kValue } from '../../../../../util/constants.js';
-import {
- f32,
- i32,
- u32,
- f16,
- TypeF32,
- TypeI32,
- TypeU32,
- TypeF16,
- TypeVec,
- Vector,
- Scalar,
- toVector,
-} from '../../../../../util/conversion.js';
-import { FPInterval, FP } from '../../../../../util/floating_point.js';
-import {
- scalarF32Range,
- fullI32Range,
- fullU32Range,
- scalarF16Range,
- linearRange,
- isSubnormalNumberF32,
- isSubnormalNumberF16,
- cartesianProduct,
- isFiniteF32,
- isFiniteF16,
-} from '../../../../../util/math.js';
-import {
- reinterpretI32AsF32,
- reinterpretI32AsU32,
- reinterpretF32AsI32,
- reinterpretF32AsU32,
- reinterpretU32AsF32,
- reinterpretU32AsI32,
- reinterpretU16AsF16,
- reinterpretF16AsU16,
-} from '../../../../../util/reinterpret.js';
-import { makeCaseCache } from '../../case_cache.js';
-import { allInputSources, run, ShaderBuilder } from '../../expression.js';
+import { TypeF16, TypeF32, TypeI32, TypeU32, TypeVec } from '../../../../../util/conversion.js';
+import { ShaderBuilder, allInputSources, run } from '../../expression.js';
+import { d } from './bitcast.cache.js';
import { builtinWithPredeclaration } from './builtin.js';
export const g = makeTestGroup(GPUTest);
-const numNaNs = 11;
-const f32InfAndNaNInU32: number[] = [
- // Cover NaNs evenly in integer space.
- // The positive NaN with the lowest integer representation is the integer
- // for infinity, plus one.
- // The positive NaN with the highest integer representation is i32.max (!)
- ...linearRange(kBit.f32.positive.infinity + 1, kBit.i32.positive.max, numNaNs),
- // The negative NaN with the lowest integer representation is the integer
- // for negative infinity, plus one.
- // The negative NaN with the highest integer representation is u32.max (!)
- ...linearRange(kBit.f32.negative.infinity + 1, kBit.u32.max, numNaNs),
- kBit.f32.positive.infinity,
- kBit.f32.negative.infinity,
-];
-const f32InfAndNaNInF32 = f32InfAndNaNInU32.map(u => reinterpretU32AsF32(u));
-const f32InfAndNaNInI32 = f32InfAndNaNInU32.map(u => reinterpretU32AsI32(u));
-
-const f32ZerosInU32 = [0, kBit.f32.negative.zero];
-const f32ZerosInF32 = f32ZerosInU32.map(u => reinterpretU32AsF32(u));
-const f32ZerosInI32 = f32ZerosInU32.map(u => reinterpretU32AsI32(u));
-const f32ZerosInterval: FPInterval = new FPInterval('f32', -0.0, 0.0);
-
-// f32FiniteRange is a list of finite f32s. fullF32Range() already
-// has +0, we only need to add -0.
-const f32FiniteRange: number[] = [...scalarF32Range(), kValue.f32.negative.zero];
-const f32RangeWithInfAndNaN: number[] = [...f32FiniteRange, ...f32InfAndNaNInF32];
-
-// F16 values, finite, Inf/NaN, and zeros. Represented in float and u16.
-const f16FiniteInF16: number[] = [...scalarF16Range(), kValue.f16.negative.zero];
-const f16FiniteInU16: number[] = f16FiniteInF16.map(u => reinterpretF16AsU16(u));
-
-const f16InfAndNaNInU16: number[] = [
- // Cover NaNs evenly in integer space.
- // The positive NaN with the lowest integer representation is the integer
- // for infinity, plus one.
- // The positive NaN with the highest integer representation is u16 0x7fff i.e. 32767.
- ...linearRange(kBit.f16.positive.infinity + 1, 32767, numNaNs).map(v => Math.ceil(v)),
- // The negative NaN with the lowest integer representation is the integer
- // for negative infinity, plus one.
- // The negative NaN with the highest integer representation is u16 0xffff i.e. 65535
- ...linearRange(kBit.f16.negative.infinity + 1, 65535, numNaNs).map(v => Math.floor(v)),
- kBit.f16.positive.infinity,
- kBit.f16.negative.infinity,
-];
-const f16InfAndNaNInF16 = f16InfAndNaNInU16.map(u => reinterpretU16AsF16(u));
-
-const f16ZerosInU16 = [kBit.f16.negative.zero, 0];
-
-// f16 interval that match +/-0.0.
-const f16ZerosInterval: FPInterval = new FPInterval('f16', -0.0, 0.0);
-
-/**
- * @returns an u32 whose lower and higher 16bits are the two elements of the
- * given array of two u16 respectively, in little-endian.
- */
-function u16x2ToU32(u16x2: readonly number[]): number {
- assert(u16x2.length === 2);
- // Create a DataView with 4 bytes buffer.
- const buffer = new ArrayBuffer(4);
- const view = new DataView(buffer);
- // Enforce little-endian.
- view.setUint16(0, u16x2[0], true);
- view.setUint16(2, u16x2[1], true);
- return view.getUint32(0, true);
-}
-
-/**
- * @returns an array of two u16, respectively the lower and higher 16bits of
- * given u32 in little-endian.
- */
-function u32ToU16x2(u32: number): number[] {
- // Create a DataView with 4 bytes buffer.
- const buffer = new ArrayBuffer(4);
- const view = new DataView(buffer);
- // Enforce little-endian.
- view.setUint32(0, u32, true);
- return [view.getUint16(0, true), view.getUint16(2, true)];
-}
-
-/**
- * @returns a vec2 from an array of two u16, each reinterpreted as f16.
- */
-function u16x2ToVec2F16(u16x2: number[]): Vector {
- assert(u16x2.length === 2);
- return toVector(u16x2.map(reinterpretU16AsF16), f16);
-}
-
-/**
- * @returns a vec4 from an array of four u16, each reinterpreted as f16.
- */
-function u16x4ToVec4F16(u16x4: number[]): Vector {
- assert(u16x4.length === 4);
- return toVector(u16x4.map(reinterpretU16AsF16), f16);
-}
-
-/**
- * @returns true if and only if a given u32 can bitcast to a vec2 with all elements
- * being finite f16 values.
- */
-function canU32BitcastToFiniteVec2F16(u32: number): boolean {
- return u32ToU16x2(u32)
- .map(u16 => isFiniteF16(reinterpretU16AsF16(u16)))
- .reduce((a, b) => a && b, true);
-}
-
-/**
- * @returns an array of N elements with the i-th element being an array of len elements
- * [a_i, a_((i+1)%N), ..., a_((i+len-1)%N)], for the input array of N element [a_1, ... a_N]
- * and the given len. For example, slidingSlice([1, 2, 3], 2) result in
- * [[1, 2], [2, 3], [3, 1]].
- * This helper function is used for generating vector cases from scalar values array.
- */
-function slidingSlice(input: number[], len: number) {
- const result: number[][] = [];
- for (let i = 0; i < input.length; i++) {
- const sub: number[] = [];
- for (let j = 0; j < len; j++) {
- sub.push(input[(i + j) % input.length]);
- }
- result.push(sub);
- }
- return result;
-}
-
-// vec2 interesting (zeros, Inf, and NaN) values for testing cases.
-// vec2 values that has at least one Inf/NaN f16 element, reinterpreted as u32/i32.
-const f16Vec2InfAndNaNInU32 = [
- ...cartesianProduct(f16InfAndNaNInU16, [...f16InfAndNaNInU16, ...f16FiniteInU16]),
- ...cartesianProduct(f16FiniteInU16, f16InfAndNaNInU16),
-].map(u16x2ToU32);
-const f16Vec2InfAndNaNInI32 = f16Vec2InfAndNaNInU32.map(u => reinterpretU32AsI32(u));
-// vec2 values with two f16 0.0 element, reinterpreted as u32/i32.
-const f16Vec2ZerosInU32 = cartesianProduct(f16ZerosInU16, f16ZerosInU16).map(u16x2ToU32);
-const f16Vec2ZerosInI32 = f16Vec2ZerosInU32.map(u => reinterpretU32AsI32(u));
-
-// i32/u32/f32 range for bitcasting to vec2
-// u32 values for bitcasting to vec2 finite, Inf, and NaN.
-const u32RangeForF16Vec2FiniteInfNaN: number[] = [
- ...fullU32Range(),
- ...f16Vec2ZerosInU32,
- ...f16Vec2InfAndNaNInU32,
-];
-// u32 values for bitcasting to finite only vec2, used for constant evaluation.
-const u32RangeForF16Vec2Finite: number[] = u32RangeForF16Vec2FiniteInfNaN.filter(
- canU32BitcastToFiniteVec2F16
-);
-// i32 values for bitcasting to vec2 finite, zeros, Inf, and NaN.
-const i32RangeForF16Vec2FiniteInfNaN: number[] = [
- ...fullI32Range(),
- ...f16Vec2ZerosInI32,
- ...f16Vec2InfAndNaNInI32,
-];
-// i32 values for bitcasting to finite only vec2, used for constant evaluation.
-const i32RangeForF16Vec2Finite: number[] = i32RangeForF16Vec2FiniteInfNaN.filter(u =>
- canU32BitcastToFiniteVec2F16(reinterpretI32AsU32(u))
-);
-// f32 values with finite/Inf/NaN f32, for bitcasting to vec2 finite, zeros, Inf, and NaN.
-const f32RangeWithInfAndNaNForF16Vec2FiniteInfNaN: number[] = [
- ...f32RangeWithInfAndNaN,
- ...u32RangeForF16Vec2FiniteInfNaN.map(reinterpretU32AsF32),
-];
-// Finite f32 values for bitcasting to finite only vec2, used for constant evaluation.
-const f32FiniteRangeForF16Vec2Finite: number[] = f32RangeWithInfAndNaNForF16Vec2FiniteInfNaN
- .filter(isFiniteF32)
- .filter(u => canU32BitcastToFiniteVec2F16(reinterpretF32AsU32(u)));
-
-// vec2 cases for bitcasting to i32/u32/f32, by combining f16 values into pairs
-const f16Vec2FiniteInU16x2 = slidingSlice(f16FiniteInU16, 2);
-const f16Vec2FiniteInfNanInU16x2 = slidingSlice([...f16FiniteInU16, ...f16InfAndNaNInU16], 2);
-// vec4 cases for bitcasting to vec2, by combining f16 values 4-by-4
-const f16Vec2FiniteInU16x4 = slidingSlice(f16FiniteInU16, 4);
-const f16Vec2FiniteInfNanInU16x4 = slidingSlice([...f16FiniteInU16, ...f16InfAndNaNInU16], 4);
-
-// alwaysPass comparator for i32/u32/f32 cases. For f32/f16 we also use unbound interval, which
-// allow per-element unbounded expectation for vector.
-const anyF32 = alwaysPass('any f32');
-const anyI32 = alwaysPass('any i32');
-const anyU32 = alwaysPass('any u32');
-
-// Unbounded FPInterval
-const f32UnboundedInterval = FP.f32.constants().unboundedInterval;
-const f16UnboundedInterval = FP.f16.constants().unboundedInterval;
-
-// i32 and u32 cases for bitcasting to f32.
-// i32 cases for bitcasting to f32 finite, zeros, Inf, and NaN.
-const i32RangeForF32FiniteInfNaN: number[] = [
- ...fullI32Range(),
- ...f32ZerosInI32,
- ...f32InfAndNaNInI32,
-];
-// i32 cases for bitcasting to f32 finite only.
-const i32RangeForF32Finite: number[] = i32RangeForF32FiniteInfNaN.filter(i =>
- isFiniteF32(reinterpretI32AsF32(i))
-);
-// u32 cases for bitcasting to f32 finite, zeros, Inf, and NaN.
-const u32RangeForF32FiniteInfNaN: number[] = [
- ...fullU32Range(),
- ...f32ZerosInU32,
- ...f32InfAndNaNInU32,
-];
-// u32 cases for bitcasting to f32 finite only.
-const u32RangeForF32Finite: number[] = u32RangeForF32FiniteInfNaN.filter(u =>
- isFiniteF32(reinterpretU32AsF32(u))
-);
-
-/**
- * @returns a Comparator for checking if a f32 value is a valid
- * bitcast conversion from f32.
- */
-function bitcastF32ToF32Comparator(f: number): Comparator {
- if (!isFiniteF32(f)) return anyF32;
- const acceptable: number[] = [f, ...(isSubnormalNumberF32(f) ? f32ZerosInF32 : [])];
- return anyOf(...acceptable.map(f32));
-}
-
-/**
- * @returns a Comparator for checking if a u32 value is a valid
- * bitcast conversion from f32.
- */
-function bitcastF32ToU32Comparator(f: number): Comparator {
- if (!isFiniteF32(f)) return anyU32;
- const acceptable: number[] = [
- reinterpretF32AsU32(f),
- ...(isSubnormalNumberF32(f) ? f32ZerosInU32 : []),
- ];
- return anyOf(...acceptable.map(u32));
-}
-
-/**
- * @returns a Comparator for checking if a i32 value is a valid
- * bitcast conversion from f32.
- */
-function bitcastF32ToI32Comparator(f: number): Comparator {
- if (!isFiniteF32(f)) return anyI32;
- const acceptable: number[] = [
- reinterpretF32AsI32(f),
- ...(isSubnormalNumberF32(f) ? f32ZerosInI32 : []),
- ];
- return anyOf(...acceptable.map(i32));
-}
-
-/**
- * @returns a Comparator for checking if a f32 value is a valid
- * bitcast conversion from i32.
- */
-function bitcastI32ToF32Comparator(i: number): Comparator {
- const f: number = reinterpretI32AsF32(i);
- if (!isFiniteF32(f)) return anyI32;
- // Positive or negative zero bit pattern map to any zero.
- if (f32ZerosInI32.includes(i)) return anyOf(...f32ZerosInF32.map(f32));
- const acceptable: number[] = [f, ...(isSubnormalNumberF32(f) ? f32ZerosInF32 : [])];
- return anyOf(...acceptable.map(f32));
-}
-
-/**
- * @returns a Comparator for checking if a f32 value is a valid
- * bitcast conversion from u32.
- */
-function bitcastU32ToF32Comparator(u: number): Comparator {
- const f: number = reinterpretU32AsF32(u);
- if (!isFiniteF32(f)) return anyU32;
- // Positive or negative zero bit pattern map to any zero.
- if (f32ZerosInU32.includes(u)) return anyOf(...f32ZerosInF32.map(f32));
- const acceptable: number[] = [f, ...(isSubnormalNumberF32(f) ? f32ZerosInF32 : [])];
- return anyOf(...acceptable.map(f32));
-}
-
-/**
- * @returns an array of expected f16 FPInterval for the given bitcasted f16 value, which may be
- * subnormal, Inf, or NaN. Test cases that bitcasted to vector of f16 use this function to get
- * per-element expectation and build vector expectation using cartesianProduct.
- */
-function generateF16ExpectationIntervals(bitcastedF16Value: number): FPInterval[] {
- // If the bitcasted f16 value is inf or nan, the result is unbounded
- if (!isFiniteF16(bitcastedF16Value)) {
- return [f16UnboundedInterval];
- }
- // If the casted f16 value is +/-0.0, the result can be one of both. Note that in JS -0.0 === 0.0.
- if (bitcastedF16Value === 0.0) {
- return [f16ZerosInterval];
- }
- const exactInterval = FP.f16.toInterval(bitcastedF16Value);
- // If the casted f16 value is subnormal, it also may be flushed to +/-0.0.
- return [exactInterval, ...(isSubnormalNumberF16(bitcastedF16Value) ? [f16ZerosInterval] : [])];
-}
-
-/**
- * @returns a Comparator for checking if a f16 value is a valid
- * bitcast conversion from f16.
- */
-function bitcastF16ToF16Comparator(f: number): Comparator {
- if (!isFiniteF16(f)) return anyOf(f16UnboundedInterval);
- return anyOf(...generateF16ExpectationIntervals(f));
-}
-
-/**
- * @returns a Comparator for checking if a vec2 is a valid bitcast
- * conversion from u32.
- */
-function bitcastU32ToVec2F16Comparator(u: number): Comparator {
- const bitcastedVec2F16InU16x2 = u32ToU16x2(u).map(reinterpretU16AsF16);
- // Generate expection for vec2 f16 result, by generating expected intervals for each elements and
- // then do cartesian product.
- const expectedIntervalsCombination = cartesianProduct(
- ...bitcastedVec2F16InU16x2.map(generateF16ExpectationIntervals)
- );
- return anyOf(...expectedIntervalsCombination);
-}
-
-/**
- * @returns a Comparator for checking if a vec2 value is a valid
- * bitcast conversion from i32.
- */
-function bitcastI32ToVec2F16Comparator(i: number): Comparator {
- const bitcastedVec2F16InU16x2 = u32ToU16x2(reinterpretI32AsU32(i)).map(reinterpretU16AsF16);
- // Generate expection for vec2 f16 result, by generating expected intervals for each elements and
- // then do cartesian product.
- const expectedIntervalsCombination = cartesianProduct(
- ...bitcastedVec2F16InU16x2.map(generateF16ExpectationIntervals)
- );
- return anyOf(...expectedIntervalsCombination);
-}
-
-/**
- * @returns a Comparator for checking if a vec2 value is a valid
- * bitcast conversion from f32.
- */
-function bitcastF32ToVec2F16Comparator(f: number): Comparator {
- // If input f32 is not finite, it can be evaluated to any value and thus any result f16 vec2 is
- // possible.
- if (!isFiniteF32(f)) {
- return anyOf([f16UnboundedInterval, f16UnboundedInterval]);
- }
- const bitcastedVec2F16InU16x2 = u32ToU16x2(reinterpretF32AsU32(f)).map(reinterpretU16AsF16);
- // Generate expection for vec2 f16 result, by generating expected intervals for each elements and
- // then do cartesian product.
- const expectedIntervalsCombination = cartesianProduct(
- ...bitcastedVec2F16InU16x2.map(generateF16ExpectationIntervals)
- );
- return anyOf(...expectedIntervalsCombination);
-}
-
-/**
- * @returns a Comparator for checking if a vec4 is a valid
- * bitcast conversion from vec2.
- */
-function bitcastVec2U32ToVec4F16Comparator(u32x2: number[]): Comparator {
- assert(u32x2.length === 2);
- const bitcastedVec4F16InU16x4 = u32x2.flatMap(u32ToU16x2).map(reinterpretU16AsF16);
- // Generate expection for vec4 f16 result, by generating expected intervals for each elements and
- // then do cartesian product.
- const expectedIntervalsCombination = cartesianProduct(
- ...bitcastedVec4F16InU16x4.map(generateF16ExpectationIntervals)
- );
- return anyOf(...expectedIntervalsCombination);
-}
-
-/**
- * @returns a Comparator for checking if a vec4 is a valid
- * bitcast conversion from vec2.
- */
-function bitcastVec2I32ToVec4F16Comparator(i32x2: number[]): Comparator {
- assert(i32x2.length === 2);
- const bitcastedVec4F16InU16x4 = i32x2
- .map(reinterpretI32AsU32)
- .flatMap(u32ToU16x2)
- .map(reinterpretU16AsF16);
- // Generate expection for vec4 f16 result, by generating expected intervals for each elements and
- // then do cartesian product.
- const expectedIntervalsCombination = cartesianProduct(
- ...bitcastedVec4F16InU16x4.map(generateF16ExpectationIntervals)
- );
- return anyOf(...expectedIntervalsCombination);
-}
-
-/**
- * @returns a Comparator for checking if a vec4 is a valid
- * bitcast conversion from vec2.
- */
-function bitcastVec2F32ToVec4F16Comparator(f32x2: number[]): Comparator {
- assert(f32x2.length === 2);
- const bitcastedVec4F16InU16x4 = f32x2
- .map(reinterpretF32AsU32)
- .flatMap(u32ToU16x2)
- .map(reinterpretU16AsF16);
- // Generate expection for vec4 f16 result, by generating expected intervals for each elements and
- // then do cartesian product.
- const expectedIntervalsCombination = cartesianProduct(
- ...bitcastedVec4F16InU16x4.map(generateF16ExpectationIntervals)
- );
- return anyOf(...expectedIntervalsCombination);
-}
-
-// Structure that store the expectations of a single 32bit scalar/element bitcasted from two f16.
-interface ExpectionFor32BitsScalarFromF16x2 {
- // possibleExpectations is Scalar array if the expectation is for i32/u32 and FPInterval array for
- // f32. Note that if the expectation for i32/u32 is unbound, possibleExpectations is meaningless.
- possibleExpectations: (Scalar | FPInterval)[];
- isUnbounded: boolean;
-}
-
-/**
- * @returns the array of possible 16bits, represented in u16, that bitcasted
- * from a given finite f16 represented in u16, handling the possible subnormal
- * flushing. Used to build up 32bits or larger results.
- */
-function possibleBitsInU16FromFiniteF16InU16(f16InU16: number): number[] {
- const h = reinterpretU16AsF16(f16InU16);
- assert(isFiniteF16(h));
- return [f16InU16, ...(isSubnormalNumberF16(h) ? f16ZerosInU16 : [])];
-}
-
-/**
- * @returns the expectation for a single 32bit scalar bitcasted from given pair of
- * f16, result in ExpectionFor32BitsScalarFromF16x2.
- */
-function possible32BitScalarIntervalsFromF16x2(
- f16x2InU16x2: number[],
- type: 'i32' | 'u32' | 'f32'
-): ExpectionFor32BitsScalarFromF16x2 {
- assert(f16x2InU16x2.length === 2);
- let reinterpretFromU32: (x: number) => number;
- let expectationsForValue: (x: number) => Scalar[] | FPInterval[];
- let unboundedExpectations: FPInterval[] | Scalar[];
- if (type === 'u32') {
- reinterpretFromU32 = (x: number) => x;
- expectationsForValue = x => [u32(x)];
- // Scalar expectation can not express "unbounded" for i32 and u32, so use 0 here as a
- // placeholder, and the possibleExpectations should be ignored if the result is unbounded.
- unboundedExpectations = [u32(0)];
- } else if (type === 'i32') {
- reinterpretFromU32 = (x: number) => reinterpretU32AsI32(x);
- expectationsForValue = x => [i32(x)];
- // Scalar expectation can not express "unbounded" for i32 and u32, so use 0 here as a
- // placeholder, and the possibleExpectations should be ignored if the result is unbounded.
- unboundedExpectations = [i32(0)];
- } else {
- assert(type === 'f32');
- reinterpretFromU32 = (x: number) => reinterpretU32AsF32(x);
- expectationsForValue = x => {
- // Handle the possible Inf/NaN/zeros and subnormal cases for f32 result.
- if (!isFiniteF32(x)) {
- return [f32UnboundedInterval];
- }
- // If the casted f16 value is +/-0.0, the result can be one of both. Note that in JS -0.0 === 0.0.
- if (x === 0.0) {
- return [f32ZerosInterval];
- }
- const exactInterval = FP.f32.toInterval(x);
- // If the casted f16 value is subnormal, it also may be flushed to +/-0.0.
- return [exactInterval, ...(isSubnormalNumberF32(x) ? [f32ZerosInterval] : [])];
- };
- unboundedExpectations = [f32UnboundedInterval];
- }
- // Return unbounded expection if f16 Inf/NaN occurs
- if (
- !isFiniteF16(reinterpretU16AsF16(f16x2InU16x2[0])) ||
- !isFiniteF16(reinterpretU16AsF16(f16x2InU16x2[1]))
- ) {
- return { possibleExpectations: unboundedExpectations, isUnbounded: true };
- }
- const possibleU16Bits = f16x2InU16x2.map(possibleBitsInU16FromFiniteF16InU16);
- const possibleExpectations = cartesianProduct(...possibleU16Bits).flatMap(
- (possibleBitsU16x2: readonly number[]) => {
- assert(possibleBitsU16x2.length === 2);
- return expectationsForValue(reinterpretFromU32(u16x2ToU32(possibleBitsU16x2)));
- }
- );
- return { possibleExpectations, isUnbounded: false };
-}
-
-/**
- * @returns a Comparator for checking if a u32 value is a valid
- * bitcast conversion from vec2 f16.
- */
-function bitcastVec2F16ToU32Comparator(vec2F16InU16x2: number[]): Comparator {
- assert(vec2F16InU16x2.length === 2);
- const expectations = possible32BitScalarIntervalsFromF16x2(vec2F16InU16x2, 'u32');
- // Return alwaysPass if result is expected unbounded.
- if (expectations.isUnbounded) {
- return anyU32;
- }
- return anyOf(...expectations.possibleExpectations);
-}
-
-/**
- * @returns a Comparator for checking if a i32 value is a valid
- * bitcast conversion from vec2 f16.
- */
-function bitcastVec2F16ToI32Comparator(vec2F16InU16x2: number[]): Comparator {
- assert(vec2F16InU16x2.length === 2);
- const expectations = possible32BitScalarIntervalsFromF16x2(vec2F16InU16x2, 'i32');
- // Return alwaysPass if result is expected unbounded.
- if (expectations.isUnbounded) {
- return anyI32;
- }
- return anyOf(...expectations.possibleExpectations);
-}
-
-/**
- * @returns a Comparator for checking if a i32 value is a valid
- * bitcast conversion from vec2 f16.
- */
-function bitcastVec2F16ToF32Comparator(vec2F16InU16x2: number[]): Comparator {
- assert(vec2F16InU16x2.length === 2);
- const expectations = possible32BitScalarIntervalsFromF16x2(vec2F16InU16x2, 'f32');
- // Return alwaysPass if result is expected unbounded.
- if (expectations.isUnbounded) {
- return anyF32;
- }
- return anyOf(...expectations.possibleExpectations);
-}
-
-/**
- * @returns a Comparator for checking if a vec2 u32 value is a valid
- * bitcast conversion from vec4 f16.
- */
-function bitcastVec4F16ToVec2U32Comparator(vec4F16InU16x4: number[]): Comparator {
- assert(vec4F16InU16x4.length === 4);
- const expectationsPerElement = [vec4F16InU16x4.slice(0, 2), vec4F16InU16x4.slice(2, 4)].map(e =>
- possible32BitScalarIntervalsFromF16x2(e, 'u32')
- );
- // Return alwaysPass if any element is expected unbounded. Although it may be only one unbounded
- // element in the result vector, currently we don't have a way to build a comparator that expect
- // only one element of i32/u32 vector unbounded.
- if (expectationsPerElement.map(e => e.isUnbounded).reduce((a, b) => a || b, false)) {
- return alwaysPass('any vec2');
- }
- return anyOf(
- ...cartesianProduct(...expectationsPerElement.map(e => e.possibleExpectations)).map(
- e => new Vector(e as Scalar[])
- )
- );
-}
-
-/**
- * @returns a Comparator for checking if a vec2 i32 value is a valid
- * bitcast conversion from vec4 f16.
- */
-function bitcastVec4F16ToVec2I32Comparator(vec4F16InU16x4: number[]): Comparator {
- assert(vec4F16InU16x4.length === 4);
- const expectationsPerElement = [vec4F16InU16x4.slice(0, 2), vec4F16InU16x4.slice(2, 4)].map(e =>
- possible32BitScalarIntervalsFromF16x2(e, 'i32')
- );
- // Return alwaysPass if any element is expected unbounded. Although it may be only one unbounded
- // element in the result vector, currently we don't have a way to build a comparator that expect
- // only one element of i32/u32 vector unbounded.
- if (expectationsPerElement.map(e => e.isUnbounded).reduce((a, b) => a || b, false)) {
- return alwaysPass('any vec2');
- }
- return anyOf(
- ...cartesianProduct(...expectationsPerElement.map(e => e.possibleExpectations)).map(
- e => new Vector(e as Scalar[])
- )
- );
-}
-
-/**
- * @returns a Comparator for checking if a vec2 f32 value is a valid
- * bitcast conversion from vec4 f16.
- */
-function bitcastVec4F16ToVec2F32Comparator(vec4F16InU16x4: number[]): Comparator {
- assert(vec4F16InU16x4.length === 4);
- const expectationsPerElement = [vec4F16InU16x4.slice(0, 2), vec4F16InU16x4.slice(2, 4)].map(e =>
- possible32BitScalarIntervalsFromF16x2(e, 'f32')
- );
- return anyOf(
- ...cartesianProduct(...expectationsPerElement.map(e => e.possibleExpectations)).map(e => [
- e[0] as FPInterval,
- e[1] as FPInterval,
- ])
- );
-}
-
-export const d = makeCaseCache('bitcast', {
- // Identity Cases
- i32_to_i32: () => fullI32Range().map(e => ({ input: i32(e), expected: i32(e) })),
- u32_to_u32: () => fullU32Range().map(e => ({ input: u32(e), expected: u32(e) })),
- f32_inf_nan_to_f32: () =>
- f32RangeWithInfAndNaN.map(e => ({
- input: f32(e),
- expected: bitcastF32ToF32Comparator(e),
- })),
- f32_to_f32: () =>
- f32FiniteRange.map(e => ({ input: f32(e), expected: bitcastF32ToF32Comparator(e) })),
- f16_inf_nan_to_f16: () =>
- [...f16FiniteInF16, ...f16InfAndNaNInF16].map(e => ({
- input: f16(e),
- expected: bitcastF16ToF16Comparator(e),
- })),
- f16_to_f16: () =>
- f16FiniteInF16.map(e => ({ input: f16(e), expected: bitcastF16ToF16Comparator(e) })),
-
- // i32,u32,f32 to different i32,u32,f32
- i32_to_u32: () => fullI32Range().map(e => ({ input: i32(e), expected: u32(e) })),
- i32_to_f32: () =>
- i32RangeForF32Finite.map(e => ({
- input: i32(e),
- expected: bitcastI32ToF32Comparator(e),
- })),
- i32_to_f32_inf_nan: () =>
- i32RangeForF32FiniteInfNaN.map(e => ({
- input: i32(e),
- expected: bitcastI32ToF32Comparator(e),
- })),
- u32_to_i32: () => fullU32Range().map(e => ({ input: u32(e), expected: i32(e) })),
- u32_to_f32: () =>
- u32RangeForF32Finite.map(e => ({
- input: u32(e),
- expected: bitcastU32ToF32Comparator(e),
- })),
- u32_to_f32_inf_nan: () =>
- u32RangeForF32FiniteInfNaN.map(e => ({
- input: u32(e),
- expected: bitcastU32ToF32Comparator(e),
- })),
- f32_inf_nan_to_i32: () =>
- f32RangeWithInfAndNaN.map(e => ({
- input: f32(e),
- expected: bitcastF32ToI32Comparator(e),
- })),
- f32_to_i32: () =>
- f32FiniteRange.map(e => ({ input: f32(e), expected: bitcastF32ToI32Comparator(e) })),
-
- f32_inf_nan_to_u32: () =>
- f32RangeWithInfAndNaN.map(e => ({
- input: f32(e),
- expected: bitcastF32ToU32Comparator(e),
- })),
- f32_to_u32: () =>
- f32FiniteRange.map(e => ({ input: f32(e), expected: bitcastF32ToU32Comparator(e) })),
-
- // i32,u32,f32 to vec2
- u32_to_vec2_f16_inf_nan: () =>
- u32RangeForF16Vec2FiniteInfNaN.map(e => ({
- input: u32(e),
- expected: bitcastU32ToVec2F16Comparator(e),
- })),
- u32_to_vec2_f16: () =>
- u32RangeForF16Vec2Finite.map(e => ({
- input: u32(e),
- expected: bitcastU32ToVec2F16Comparator(e),
- })),
- i32_to_vec2_f16_inf_nan: () =>
- i32RangeForF16Vec2FiniteInfNaN.map(e => ({
- input: i32(e),
- expected: bitcastI32ToVec2F16Comparator(e),
- })),
- i32_to_vec2_f16: () =>
- i32RangeForF16Vec2Finite.map(e => ({
- input: i32(e),
- expected: bitcastI32ToVec2F16Comparator(e),
- })),
- f32_inf_nan_to_vec2_f16_inf_nan: () =>
- f32RangeWithInfAndNaNForF16Vec2FiniteInfNaN.map(e => ({
- input: f32(e),
- expected: bitcastF32ToVec2F16Comparator(e),
- })),
- f32_to_vec2_f16: () =>
- f32FiniteRangeForF16Vec2Finite.map(e => ({
- input: f32(e),
- expected: bitcastF32ToVec2F16Comparator(e),
- })),
-
- // vec2, vec2, vec2 to vec4
- vec2_i32_to_vec4_f16_inf_nan: () =>
- slidingSlice(i32RangeForF16Vec2FiniteInfNaN, 2).map(e => ({
- input: toVector(e, i32),
- expected: bitcastVec2I32ToVec4F16Comparator(e),
- })),
- vec2_i32_to_vec4_f16: () =>
- slidingSlice(i32RangeForF16Vec2Finite, 2).map(e => ({
- input: toVector(e, i32),
- expected: bitcastVec2I32ToVec4F16Comparator(e),
- })),
- vec2_u32_to_vec4_f16_inf_nan: () =>
- slidingSlice(u32RangeForF16Vec2FiniteInfNaN, 2).map(e => ({
- input: toVector(e, u32),
- expected: bitcastVec2U32ToVec4F16Comparator(e),
- })),
- vec2_u32_to_vec4_f16: () =>
- slidingSlice(u32RangeForF16Vec2Finite, 2).map(e => ({
- input: toVector(e, u32),
- expected: bitcastVec2U32ToVec4F16Comparator(e),
- })),
- vec2_f32_inf_nan_to_vec4_f16_inf_nan: () =>
- slidingSlice(f32RangeWithInfAndNaNForF16Vec2FiniteInfNaN, 2).map(e => ({
- input: toVector(e, f32),
- expected: bitcastVec2F32ToVec4F16Comparator(e),
- })),
- vec2_f32_to_vec4_f16: () =>
- slidingSlice(f32FiniteRangeForF16Vec2Finite, 2).map(e => ({
- input: toVector(e, f32),
- expected: bitcastVec2F32ToVec4F16Comparator(e),
- })),
-
- // vec2 to i32, u32, f32
- vec2_f16_to_u32: () =>
- f16Vec2FiniteInU16x2.map(e => ({
- input: u16x2ToVec2F16(e),
- expected: bitcastVec2F16ToU32Comparator(e),
- })),
- vec2_f16_inf_nan_to_u32: () =>
- f16Vec2FiniteInfNanInU16x2.map(e => ({
- input: u16x2ToVec2F16(e),
- expected: bitcastVec2F16ToU32Comparator(e),
- })),
- vec2_f16_to_i32: () =>
- f16Vec2FiniteInU16x2.map(e => ({
- input: u16x2ToVec2F16(e),
- expected: bitcastVec2F16ToI32Comparator(e),
- })),
- vec2_f16_inf_nan_to_i32: () =>
- f16Vec2FiniteInfNanInU16x2.map(e => ({
- input: u16x2ToVec2F16(e),
- expected: bitcastVec2F16ToI32Comparator(e),
- })),
- vec2_f16_to_f32_finite: () =>
- f16Vec2FiniteInU16x2
- .filter(u16x2 => isFiniteF32(reinterpretU32AsF32(u16x2ToU32(u16x2))))
- .map(e => ({
- input: u16x2ToVec2F16(e),
- expected: bitcastVec2F16ToF32Comparator(e),
- })),
- vec2_f16_inf_nan_to_f32: () =>
- f16Vec2FiniteInfNanInU16x2.map(e => ({
- input: u16x2ToVec2F16(e),
- expected: bitcastVec2F16ToF32Comparator(e),
- })),
-
- // vec4 to vec2 of i32, u32, f32
- vec4_f16_to_vec2_u32: () =>
- f16Vec2FiniteInU16x4.map(e => ({
- input: u16x4ToVec4F16(e),
- expected: bitcastVec4F16ToVec2U32Comparator(e),
- })),
- vec4_f16_inf_nan_to_vec2_u32: () =>
- f16Vec2FiniteInfNanInU16x4.map(e => ({
- input: u16x4ToVec4F16(e),
- expected: bitcastVec4F16ToVec2U32Comparator(e),
- })),
- vec4_f16_to_vec2_i32: () =>
- f16Vec2FiniteInU16x4.map(e => ({
- input: u16x4ToVec4F16(e),
- expected: bitcastVec4F16ToVec2I32Comparator(e),
- })),
- vec4_f16_inf_nan_to_vec2_i32: () =>
- f16Vec2FiniteInfNanInU16x4.map(e => ({
- input: u16x4ToVec4F16(e),
- expected: bitcastVec4F16ToVec2I32Comparator(e),
- })),
- vec4_f16_to_vec2_f32_finite: () =>
- f16Vec2FiniteInU16x4
- .filter(
- u16x4 =>
- isFiniteF32(reinterpretU32AsF32(u16x2ToU32(u16x4.slice(0, 2)))) &&
- isFiniteF32(reinterpretU32AsF32(u16x2ToU32(u16x4.slice(2, 4))))
- )
- .map(e => ({
- input: u16x4ToVec4F16(e),
- expected: bitcastVec4F16ToVec2F32Comparator(e),
- })),
- vec4_f16_inf_nan_to_vec2_f32: () =>
- f16Vec2FiniteInfNanInU16x4.map(e => ({
- input: u16x4ToVec4F16(e),
- expected: bitcastVec4F16ToVec2F32Comparator(e),
- })),
-});
-
/**
* @returns a ShaderBuilder that generates a call to bitcast,
* using appropriate destination type, which optionally can be
diff --git a/src/webgpu/shader/execution/expression/call/builtin/ceil.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/ceil.cache.ts
new file mode 100644
index 000000000000..3141d1d1a16f
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/ceil.cache.ts
@@ -0,0 +1,25 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+const kSmallMagnitudeTestValues = [0.1, 0.9, 1.0, 1.1, 1.9, -0.1, -0.9, -1.0, -1.1, -1.9];
+
+// See https://github.com/gpuweb/cts/issues/2766 for details
+const kIssue2766Value = {
+ f32: 0x8000_0000,
+ f16: 0x8000,
+};
+
+// Cases: [f32|f16]
+const cases = (['f32', 'f16'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [...kSmallMagnitudeTestValues, kIssue2766Value[trait], ...FP[trait].scalarRange()],
+ 'unfiltered',
+ FP[trait].ceilInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('ceil', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/ceil.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/ceil.spec.ts
index 8b8f9dbbaa6a..18509efdffb9 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/ceil.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/ceil.spec.ts
@@ -10,38 +10,14 @@ Returns the ceiling of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './ceil.cache.js';
export const g = makeTestGroup(GPUTest);
-const kSmallMagnitudeTestValues = [0.1, 0.9, 1.0, 1.1, 1.9, -0.1, -0.9, -1.0, -1.1, -1.9];
-
-// See https://github.com/gpuweb/cts/issues/2766 for details
-const kIssue2766Value = {
- f32: 0x8000_0000,
- f16: 0x8000,
-};
-
-// Cases: [f32|f16]
-const cases = (['f32', 'f16'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [...kSmallMagnitudeTestValues, kIssue2766Value[trait], ...FP[trait].scalarRange()],
- 'unfiltered',
- FP[trait].ceilInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('ceil', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/clamp.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/clamp.cache.ts
new file mode 100644
index 000000000000..b28e75fd40f4
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/clamp.cache.ts
@@ -0,0 +1,96 @@
+import { kValue } from '../../../../../util/constants.js';
+import { ScalarType, TypeI32, TypeU32 } from '../../../../../util/conversion.js';
+import { FP } from '../../../../../util/floating_point.js';
+import { Case } from '../../case.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+const u32Values = [0, 1, 2, 3, 0x70000000, 0x80000000, kValue.u32.max];
+
+const i32Values = [
+ kValue.i32.negative.min,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ 0x70000000,
+ kValue.i32.positive.max,
+];
+
+/** @returns a set of clamp test cases from an ascending list of integer values */
+function generateIntegerTestCases(
+ test_values: Array,
+ type: ScalarType,
+ stage: 'const' | 'non_const'
+): Array {
+ return test_values.flatMap(low =>
+ test_values.flatMap(high =>
+ stage === 'const' && low > high
+ ? []
+ : test_values.map(e => ({
+ input: [type.create(e), type.create(low), type.create(high)],
+ expected: type.create(Math.min(Math.max(e, low), high)),
+ }))
+ )
+ );
+}
+
+function generateFloatTestCases(
+ test_values: readonly number[],
+ trait: 'f32' | 'f16' | 'abstract',
+ stage: 'const' | 'non_const'
+): Array {
+ return test_values.flatMap(low =>
+ test_values.flatMap(high =>
+ stage === 'const' && low > high
+ ? []
+ : test_values.flatMap(e => {
+ const c = FP[trait].makeScalarTripleToIntervalCase(
+ e,
+ low,
+ high,
+ stage === 'const' ? 'finite' : 'unfiltered',
+ ...FP[trait].clampIntervals
+ );
+ return c === undefined ? [] : [c];
+ })
+ )
+ );
+}
+
+// Cases: [f32|f16|abstract]_[non_]const
+// abstract_non_const is empty and unused
+const fp_cases = (['f32', 'f16', 'abstract'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ if (trait === 'abstract' && nonConst) {
+ return [];
+ }
+ return generateFloatTestCases(
+ FP[trait].sparseScalarRange(),
+ trait,
+ nonConst ? 'non_const' : 'const'
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('clamp', {
+ u32_non_const: () => {
+ return generateIntegerTestCases(u32Values, TypeU32, 'non_const');
+ },
+ u32_const: () => {
+ return generateIntegerTestCases(u32Values, TypeU32, 'const');
+ },
+ i32_non_const: () => {
+ return generateIntegerTestCases(i32Values, TypeI32, 'non_const');
+ },
+ i32_const: () => {
+ return generateIntegerTestCases(i32Values, TypeI32, 'const');
+ },
+ ...fp_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/clamp.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/clamp.spec.ts
index a2f8f52843c6..75abf1f11d8d 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/clamp.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/clamp.spec.ts
@@ -15,114 +15,20 @@ Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { kValue } from '../../../../../util/constants.js';
import {
- ScalarType,
- TypeF32,
+ TypeAbstractFloat,
TypeF16,
+ TypeF32,
TypeI32,
TypeU32,
- TypeAbstractFloat,
} from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
-import { allInputSources, Case, onlyConstInputSource, run } from '../../expression.js';
+import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './clamp.cache.js';
export const g = makeTestGroup(GPUTest);
-const u32Values = [0, 1, 2, 3, 0x70000000, 0x80000000, kValue.u32.max];
-
-const i32Values = [
- kValue.i32.negative.min,
- -3,
- -2,
- -1,
- 0,
- 1,
- 2,
- 3,
- 0x70000000,
- kValue.i32.positive.max,
-];
-
-/** @returns a set of clamp test cases from an ascending list of integer values */
-function generateIntegerTestCases(
- test_values: Array,
- type: ScalarType,
- stage: 'const' | 'non_const'
-): Array {
- return test_values.flatMap(low =>
- test_values.flatMap(high =>
- stage === 'const' && low > high
- ? []
- : test_values.map(e => ({
- input: [type.create(e), type.create(low), type.create(high)],
- expected: type.create(Math.min(Math.max(e, low), high)),
- }))
- )
- );
-}
-
-function generateFloatTestCases(
- test_values: readonly number[],
- trait: 'f32' | 'f16' | 'abstract',
- stage: 'const' | 'non_const'
-): Array {
- return test_values.flatMap(low =>
- test_values.flatMap(high =>
- stage === 'const' && low > high
- ? []
- : test_values.flatMap(e => {
- const c = FP[trait].makeScalarTripleToIntervalCase(
- e,
- low,
- high,
- stage === 'const' ? 'finite' : 'unfiltered',
- ...FP[trait].clampIntervals
- );
- return c === undefined ? [] : [c];
- })
- )
- );
-}
-
-// Cases: [f32|f16|abstract]_[non_]const
-// abstract_non_const is empty and unused
-const fp_cases = (['f32', 'f16', 'abstract'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- if (trait === 'abstract' && nonConst) {
- return [];
- }
- return generateFloatTestCases(
- FP[trait].sparseScalarRange(),
- trait,
- nonConst ? 'non_const' : 'const'
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('clamp', {
- u32_non_const: () => {
- return generateIntegerTestCases(u32Values, TypeU32, 'non_const');
- },
- u32_const: () => {
- return generateIntegerTestCases(u32Values, TypeU32, 'const');
- },
- i32_non_const: () => {
- return generateIntegerTestCases(i32Values, TypeI32, 'non_const');
- },
- i32_const: () => {
- return generateIntegerTestCases(i32Values, TypeI32, 'const');
- },
- ...fp_cases,
-});
-
g.test('abstract_int')
.specURL('https://www.w3.org/TR/WGSL/#integer-builtin-functions')
.desc(`abstract int tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/cos.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/cos.cache.ts
new file mode 100644
index 000000000000..1833f12d48e5
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/cos.cache.ts
@@ -0,0 +1,22 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]
+const cases = (['f32', 'f16'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [
+ // Well-defined accuracy range
+ ...linearRange(-Math.PI, Math.PI, 100),
+ ...FP[trait].scalarRange(),
+ ],
+ 'unfiltered',
+ FP[trait].cosInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('cos', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/cos.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/cos.spec.ts
index bd2eb6089048..5eb9081928d1 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/cos.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/cos.spec.ts
@@ -9,35 +9,14 @@ Returns the cosine of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './cos.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]
-const cases = (['f32', 'f16'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [
- // Well-defined accuracy range
- ...linearRange(-Math.PI, Math.PI, 100),
- ...FP[trait].scalarRange(),
- ],
- 'unfiltered',
- FP[trait].cosInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('cos', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/cosh.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/cosh.cache.ts
new file mode 100644
index 000000000000..e3fb7a0e7b88
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/cosh.cache.ts
@@ -0,0 +1,19 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].coshInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('cosh', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/cosh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/cosh.spec.ts
index 296e3a4b3ef8..aba7212a06e3 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/cosh.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/cosh.spec.ts
@@ -9,32 +9,14 @@ Returns the hyperbolic cosine of e. Component-wise when T is a vector
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './cosh.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].coshInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('cosh', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/cross.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/cross.cache.ts
new file mode 100644
index 000000000000..74752d3afb26
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/cross.cache.ts
@@ -0,0 +1,24 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]_[non_]const
+// abstract_non_const is empty and not used
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ if (trait === 'abstract' && nonConst) {
+ return [];
+ }
+ return FP[trait].generateVectorPairToVectorCases(
+ FP[trait].vectorRange(3),
+ FP[trait].vectorRange(3),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].crossInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('cross', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/cross.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/cross.spec.ts
index 78dc11895181..bf26a42f2f5e 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/cross.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/cross.spec.ts
@@ -9,36 +9,13 @@ Returns the cross product of e1 and e2.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeAbstractFloat, TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './cross.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16|abstract]_[non_]const
-// abstract_non_const is empty and not used
-const cases = (['f32', 'f16', 'abstract'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- if (trait === 'abstract' && nonConst) {
- return [];
- }
- return FP[trait].generateVectorPairToVectorCases(
- FP[trait].vectorRange(3),
- FP[trait].vectorRange(3),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].crossInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('cross', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/degrees.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/degrees.cache.ts
new file mode 100644
index 000000000000..2dbe8923c4cc
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/degrees.cache.ts
@@ -0,0 +1,23 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]_[non_]const
+// abstract_non_const is empty and not used
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ if (trait === 'abstract' && nonConst) {
+ return [];
+ }
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].degreesInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('degrees', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/degrees.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/degrees.spec.ts
index 4da88c5e3d68..0e52c52c11a3 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/degrees.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/degrees.spec.ts
@@ -10,35 +10,13 @@ Converts radians to degrees, approximating e1 × 180 ÷ π. Component-wise when
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './degrees.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16|abstract]_[non_]const
-// abstract_non_const is empty and not used
-const cases = (['f32', 'f16', 'abstract'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- if (trait === 'abstract' && nonConst) {
- return [];
- }
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].degreesInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('degrees', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/determinant.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/determinant.cache.ts
new file mode 100644
index 000000000000..379b42b3e63c
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/determinant.cache.ts
@@ -0,0 +1,84 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Accuracy for determinant is only defined for e, where e is an integer and
+// |e| < quadroot(2**21) [~38],
+// due to computational complexity of calculating the general solution for 4x4,
+// so custom matrices are used.
+//
+// Note: For 2x2 and 3x3 the limits are squareroot and cuberoot instead of
+// quadroot, but using the tighter 4x4 limits for all cases for simplicity.
+const kDeterminantValues = [-38, -10, -5, -1, 0, 1, 5, 10, 38];
+
+const kDeterminantMatrixValues = {
+ 2: kDeterminantValues.map((f, idx) => [
+ [idx % 4 === 0 ? f : idx, idx % 4 === 1 ? f : -idx],
+ [idx % 4 === 2 ? f : -idx, idx % 4 === 3 ? f : idx],
+ ]),
+ 3: kDeterminantValues.map((f, idx) => [
+ [idx % 9 === 0 ? f : idx, idx % 9 === 1 ? f : -idx, idx % 9 === 2 ? f : idx],
+ [idx % 9 === 3 ? f : -idx, idx % 9 === 4 ? f : idx, idx % 9 === 5 ? f : -idx],
+ [idx % 9 === 6 ? f : idx, idx % 9 === 7 ? f : -idx, idx % 9 === 8 ? f : idx],
+ ]),
+ 4: kDeterminantValues.map((f, idx) => [
+ [
+ idx % 16 === 0 ? f : idx,
+ idx % 16 === 1 ? f : -idx,
+ idx % 16 === 2 ? f : idx,
+ idx % 16 === 3 ? f : -idx,
+ ],
+ [
+ idx % 16 === 4 ? f : -idx,
+ idx % 16 === 5 ? f : idx,
+ idx % 16 === 6 ? f : -idx,
+ idx % 16 === 7 ? f : idx,
+ ],
+ [
+ idx % 16 === 8 ? f : idx,
+ idx % 16 === 9 ? f : -idx,
+ idx % 16 === 10 ? f : idx,
+ idx % 16 === 11 ? f : -idx,
+ ],
+ [
+ idx % 16 === 12 ? f : -idx,
+ idx % 16 === 13 ? f : idx,
+ idx % 16 === 14 ? f : -idx,
+ idx % 16 === 15 ? f : idx,
+ ],
+ ]),
+};
+
+// Cases: f32_matDxD_[non_]const
+const f32_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`f32_mat${dim}x${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f32.generateMatrixToScalarCases(
+ kDeterminantMatrixValues[dim],
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f32.determinantInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: f16_matDxD_[non_]const
+const f16_cases = ([2, 3, 4] as const)
+ .flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`f16_mat${dim}x${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP.f16.generateMatrixToScalarCases(
+ kDeterminantMatrixValues[dim],
+ nonConst ? 'unfiltered' : 'finite',
+ FP.f16.determinantInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('determinant', {
+ ...f32_cases,
+ ...f16_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/determinant.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/determinant.spec.ts
index f08f4f0b6b25..c628623f4378 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/determinant.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/determinant.spec.ts
@@ -8,97 +8,14 @@ Returns the determinant of e.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16, TypeMat } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32, TypeMat } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './determinant.cache.js';
export const g = makeTestGroup(GPUTest);
-// Accuracy for determinant is only defined for e, where e is an integer and
-// |e| < quadroot(2**21) [~38],
-// due to computational complexity of calculating the general solution for 4x4,
-// so custom matrices are used.
-//
-// Note: For 2x2 and 3x3 the limits are squareroot and cuberoot instead of
-// quadroot, but using the tighter 4x4 limits for all cases for simplicity.
-const kDeterminantValues = [-38, -10, -5, -1, 0, 1, 5, 10, 38];
-
-const kDeterminantMatrixValues = {
- 2: kDeterminantValues.map((f, idx) => [
- [idx % 4 === 0 ? f : idx, idx % 4 === 1 ? f : -idx],
- [idx % 4 === 2 ? f : -idx, idx % 4 === 3 ? f : idx],
- ]),
- 3: kDeterminantValues.map((f, idx) => [
- [idx % 9 === 0 ? f : idx, idx % 9 === 1 ? f : -idx, idx % 9 === 2 ? f : idx],
- [idx % 9 === 3 ? f : -idx, idx % 9 === 4 ? f : idx, idx % 9 === 5 ? f : -idx],
- [idx % 9 === 6 ? f : idx, idx % 9 === 7 ? f : -idx, idx % 9 === 8 ? f : idx],
- ]),
- 4: kDeterminantValues.map((f, idx) => [
- [
- idx % 16 === 0 ? f : idx,
- idx % 16 === 1 ? f : -idx,
- idx % 16 === 2 ? f : idx,
- idx % 16 === 3 ? f : -idx,
- ],
- [
- idx % 16 === 4 ? f : -idx,
- idx % 16 === 5 ? f : idx,
- idx % 16 === 6 ? f : -idx,
- idx % 16 === 7 ? f : idx,
- ],
- [
- idx % 16 === 8 ? f : idx,
- idx % 16 === 9 ? f : -idx,
- idx % 16 === 10 ? f : idx,
- idx % 16 === 11 ? f : -idx,
- ],
- [
- idx % 16 === 12 ? f : -idx,
- idx % 16 === 13 ? f : idx,
- idx % 16 === 14 ? f : -idx,
- idx % 16 === 15 ? f : idx,
- ],
- ]),
-};
-
-// Cases: f32_matDxD_[non_]const
-const f32_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`f32_mat${dim}x${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f32.generateMatrixToScalarCases(
- kDeterminantMatrixValues[dim],
- nonConst ? 'unfiltered' : 'finite',
- FP.f32.determinantInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: f16_matDxD_[non_]const
-const f16_cases = ([2, 3, 4] as const)
- .flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`f16_mat${dim}x${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP.f16.generateMatrixToScalarCases(
- kDeterminantMatrixValues[dim],
- nonConst ? 'unfiltered' : 'finite',
- FP.f16.determinantInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('determinant', {
- ...f32_cases,
- ...f16_cases,
-});
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#matrix-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/distance.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/distance.cache.ts
new file mode 100644
index 000000000000..0e1bf291a50f
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/distance.cache.ts
@@ -0,0 +1,41 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const scalar_cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarPairToIntervalCases(
+ FP[trait].scalarRange(),
+ FP[trait].scalarRange(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].distanceInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: [f32|f16]_vecN_[non_]const
+const vec_cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([2, 3, 4] as const).flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateVectorPairToIntervalCases(
+ FP[trait].sparseVectorRange(dim),
+ FP[trait].sparseVectorRange(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].distanceInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('distance', {
+ ...scalar_cases,
+ ...vec_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/distance.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/distance.spec.ts
index 69b9606bf0bc..ab63029ca227 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/distance.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/distance.spec.ts
@@ -10,54 +10,14 @@ Returns the distance between e1 and e2 (e.g. length(e1-e2)).
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './distance.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const scalar_cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarPairToIntervalCases(
- FP[trait].scalarRange(),
- FP[trait].scalarRange(),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].distanceInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: [f32|f16]_vecN_[non_]const
-const vec_cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([2, 3, 4] as const).flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateVectorPairToIntervalCases(
- FP[trait].sparseVectorRange(dim),
- FP[trait].sparseVectorRange(dim),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].distanceInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('distance', {
- ...scalar_cases,
- ...vec_cases,
-});
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/dot.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/dot.cache.ts
new file mode 100644
index 000000000000..979e476f85f4
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/dot.cache.ts
@@ -0,0 +1,24 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_vecN_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([2, 3, 4] as const).flatMap(N =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_vec${N}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ // vec3 and vec4 require calculating all possible permutations, so their runtime is much
+ // longer per test, so only using sparse vectors for them.
+ return FP[trait].generateVectorPairToIntervalCases(
+ N === 2 ? FP[trait].vectorRange(2) : FP[trait].sparseVectorRange(N),
+ N === 2 ? FP[trait].vectorRange(2) : FP[trait].sparseVectorRange(N),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].dotInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('dot', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/dot.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/dot.spec.ts
index c9c7266b649e..215f3879dc2e 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/dot.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/dot.spec.ts
@@ -8,37 +8,14 @@ Returns the dot product of e1 and e2.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './dot.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_vecN_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([2, 3, 4] as const).flatMap(N =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_vec${N}_${nonConst ? 'non_const' : 'const'}`]: () => {
- // vec3 and vec4 require calculating all possible permutations, so their runtime is much
- // longer per test, so only using sparse vectors for them.
- return FP[trait].generateVectorPairToIntervalCases(
- N === 2 ? FP[trait].vectorRange(2) : FP[trait].sparseVectorRange(N),
- N === 2 ? FP[trait].vectorRange(2) : FP[trait].sparseVectorRange(N),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].dotInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('dot', cases);
-
g.test('abstract_int')
.specURL('https://www.w3.org/TR/WGSL/#vector-builtin-functions')
.desc(`abstract int tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/exp.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/exp.cache.ts
new file mode 100644
index 000000000000..d294ea4f538e
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/exp.cache.ts
@@ -0,0 +1,40 @@
+import { kValue } from '../../../../../util/constants.js';
+import { FP } from '../../../../../util/floating_point.js';
+import { biasedRange, linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// floor(ln(max f32 value)) = 88, so exp(88) will be within range of a f32, but exp(89) will not
+// floor(ln(max f64 value)) = 709, so exp(709) can be handled by the testing framework, but exp(710) will misbehave
+const f32_inputs = [
+ 0, // Returns 1 by definition
+ -89, // Returns subnormal value
+ kValue.f32.negative.min, // Closest to returning 0 as possible
+ ...biasedRange(kValue.f32.negative.max, -88, 100),
+ ...biasedRange(kValue.f32.positive.min, 88, 100),
+ ...linearRange(89, 709, 10), // Overflows f32, but not f64
+];
+
+// floor(ln(max f16 value)) = 11, so exp(11) will be within range of a f16, but exp(12) will not
+const f16_inputs = [
+ 0, // Returns 1 by definition
+ -12, // Returns subnormal value
+ kValue.f16.negative.min, // Closest to returning 0 as possible
+ ...biasedRange(kValue.f16.negative.max, -11, 100),
+ ...biasedRange(kValue.f16.positive.min, 11, 100),
+ ...linearRange(12, 709, 10), // Overflows f16, but not f64
+];
+
+export const d = makeCaseCache('exp', {
+ f32_const: () => {
+ return FP.f32.generateScalarToIntervalCases(f32_inputs, 'finite', FP.f32.expInterval);
+ },
+ f32_non_const: () => {
+ return FP.f32.generateScalarToIntervalCases(f32_inputs, 'unfiltered', FP.f32.expInterval);
+ },
+ f16_const: () => {
+ return FP.f16.generateScalarToIntervalCases(f16_inputs, 'finite', FP.f16.expInterval);
+ },
+ f16_non_const: () => {
+ return FP.f16.generateScalarToIntervalCases(f16_inputs, 'unfiltered', FP.f16.expInterval);
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/exp.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/exp.spec.ts
index 8b1ced3cab80..ad381df01690 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/exp.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/exp.spec.ts
@@ -9,53 +9,14 @@ Returns the natural exponentiation of e1 (e.g. e^e1). Component-wise when T is a
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { kValue } from '../../../../../util/constants.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { biasedRange, linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './exp.cache.js';
export const g = makeTestGroup(GPUTest);
-// floor(ln(max f32 value)) = 88, so exp(88) will be within range of a f32, but exp(89) will not
-// floor(ln(max f64 value)) = 709, so exp(709) can be handled by the testing framework, but exp(710) will misbehave
-const f32_inputs = [
- 0, // Returns 1 by definition
- -89, // Returns subnormal value
- kValue.f32.negative.min, // Closest to returning 0 as possible
- ...biasedRange(kValue.f32.negative.max, -88, 100),
- ...biasedRange(kValue.f32.positive.min, 88, 100),
- ...linearRange(89, 709, 10), // Overflows f32, but not f64
-];
-
-// floor(ln(max f16 value)) = 11, so exp(11) will be within range of a f16, but exp(12) will not
-const f16_inputs = [
- 0, // Returns 1 by definition
- -12, // Returns subnormal value
- kValue.f16.negative.min, // Closest to returning 0 as possible
- ...biasedRange(kValue.f16.negative.max, -11, 100),
- ...biasedRange(kValue.f16.positive.min, 11, 100),
- ...linearRange(12, 709, 10), // Overflows f16, but not f64
-];
-
-export const d = makeCaseCache('exp', {
- f32_const: () => {
- return FP.f32.generateScalarToIntervalCases(f32_inputs, 'finite', FP.f32.expInterval);
- },
- f32_non_const: () => {
- return FP.f32.generateScalarToIntervalCases(f32_inputs, 'unfiltered', FP.f32.expInterval);
- },
- f16_const: () => {
- return FP.f16.generateScalarToIntervalCases(f16_inputs, 'finite', FP.f16.expInterval);
- },
- f16_non_const: () => {
- return FP.f16.generateScalarToIntervalCases(f16_inputs, 'unfiltered', FP.f16.expInterval);
- },
-});
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/exp2.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/exp2.cache.ts
new file mode 100644
index 000000000000..edb4b613baf2
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/exp2.cache.ts
@@ -0,0 +1,40 @@
+import { kValue } from '../../../../../util/constants.js';
+import { FP } from '../../../../../util/floating_point.js';
+import { biasedRange, linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// floor(log2(max f32 value)) = 127, so exp2(127) will be within range of a f32, but exp2(128) will not
+// floor(ln(max f64 value)) = 1023, so exp2(1023) can be handled by the testing framework, but exp2(1024) will misbehave
+const f32_inputs = [
+ 0, // Returns 1 by definition
+ -128, // Returns subnormal value
+ kValue.f32.negative.min, // Closest to returning 0 as possible
+ ...biasedRange(kValue.f32.negative.max, -127, 100),
+ ...biasedRange(kValue.f32.positive.min, 127, 100),
+ ...linearRange(128, 1023, 10), // Overflows f32, but not f64
+];
+
+// floor(log2(max f16 value)) = 15, so exp2(15) will be within range of a f16, but exp2(15) will not
+const f16_inputs = [
+ 0, // Returns 1 by definition
+ -16, // Returns subnormal value
+ kValue.f16.negative.min, // Closest to returning 0 as possible
+ ...biasedRange(kValue.f16.negative.max, -15, 100),
+ ...biasedRange(kValue.f16.positive.min, 15, 100),
+ ...linearRange(16, 1023, 10), // Overflows f16, but not f64
+];
+
+export const d = makeCaseCache('exp2', {
+ f32_const: () => {
+ return FP.f32.generateScalarToIntervalCases(f32_inputs, 'finite', FP.f32.exp2Interval);
+ },
+ f32_non_const: () => {
+ return FP.f32.generateScalarToIntervalCases(f32_inputs, 'unfiltered', FP.f32.exp2Interval);
+ },
+ f16_const: () => {
+ return FP.f16.generateScalarToIntervalCases(f16_inputs, 'finite', FP.f16.exp2Interval);
+ },
+ f16_non_const: () => {
+ return FP.f16.generateScalarToIntervalCases(f16_inputs, 'unfiltered', FP.f16.exp2Interval);
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/exp2.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/exp2.spec.ts
index 67e123cb3012..cf0e3c3cbe81 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/exp2.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/exp2.spec.ts
@@ -9,53 +9,14 @@ Returns 2 raised to the power e (e.g. 2^e). Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { kValue } from '../../../../../util/constants.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { biasedRange, linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './exp2.cache.js';
export const g = makeTestGroup(GPUTest);
-// floor(log2(max f32 value)) = 127, so exp2(127) will be within range of a f32, but exp2(128) will not
-// floor(ln(max f64 value)) = 1023, so exp2(1023) can be handled by the testing framework, but exp2(1024) will misbehave
-const f32_inputs = [
- 0, // Returns 1 by definition
- -128, // Returns subnormal value
- kValue.f32.negative.min, // Closest to returning 0 as possible
- ...biasedRange(kValue.f32.negative.max, -127, 100),
- ...biasedRange(kValue.f32.positive.min, 127, 100),
- ...linearRange(128, 1023, 10), // Overflows f32, but not f64
-];
-
-// floor(log2(max f16 value)) = 15, so exp2(15) will be within range of a f16, but exp2(15) will not
-const f16_inputs = [
- 0, // Returns 1 by definition
- -16, // Returns subnormal value
- kValue.f16.negative.min, // Closest to returning 0 as possible
- ...biasedRange(kValue.f16.negative.max, -15, 100),
- ...biasedRange(kValue.f16.positive.min, 15, 100),
- ...linearRange(16, 1023, 10), // Overflows f16, but not f64
-];
-
-export const d = makeCaseCache('exp2', {
- f32_const: () => {
- return FP.f32.generateScalarToIntervalCases(f32_inputs, 'finite', FP.f32.exp2Interval);
- },
- f32_non_const: () => {
- return FP.f32.generateScalarToIntervalCases(f32_inputs, 'unfiltered', FP.f32.exp2Interval);
- },
- f16_const: () => {
- return FP.f16.generateScalarToIntervalCases(f16_inputs, 'finite', FP.f16.exp2Interval);
- },
- f16_non_const: () => {
- return FP.f16.generateScalarToIntervalCases(f16_inputs, 'unfiltered', FP.f16.exp2Interval);
- },
-});
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/faceForward.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/faceForward.cache.ts
new file mode 100644
index 000000000000..c44c88d276a5
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/faceForward.cache.ts
@@ -0,0 +1,98 @@
+import { ROArrayArray } from '../../../../../../common/util/types.js';
+import { anyOf } from '../../../../../util/compare.js';
+import { toVector } from '../../../../../util/conversion.js';
+import { FP, FPKind, FPVector } from '../../../../../util/floating_point.js';
+import { cartesianProduct } from '../../../../../util/math.js';
+import { Case } from '../../case.js';
+import { makeCaseCache } from '../../case_cache.js';
+import { IntervalFilter } from '../../interval_filter.js';
+
+// Using a bespoke implementation of make*Case and generate*Cases here
+// since faceForwardIntervals is the only builtin with the API signature
+// (vec, vec, vec) -> vec
+//
+// Additionally faceForward has significant complexities around it due to the
+// fact that `dot` is calculated in it s operation, but the result of dot isn't
+// used to calculate the builtin's result.
+
+/**
+ * @returns a Case for `faceForward`
+ * @param kind what kind of floating point numbers being operated on
+ * @param x the `x` param for the case
+ * @param y the `y` param for the case
+ * @param z the `z` param for the case
+ * @param check what interval checking to apply
+ * */
+function makeCase(
+ kind: FPKind,
+ x: readonly number[],
+ y: readonly number[],
+ z: readonly number[],
+ check: IntervalFilter
+): Case | undefined {
+ const fp = FP[kind];
+ x = x.map(fp.quantize);
+ y = y.map(fp.quantize);
+ z = z.map(fp.quantize);
+
+ const results = FP[kind].faceForwardIntervals(x, y, z);
+ if (check === 'finite' && results.some(r => r === undefined)) {
+ return undefined;
+ }
+
+ // Stripping the undefined results, since undefined is used to signal that an OOB
+ // could occur within the calculation that isn't reflected in the result
+ // intervals.
+ const define_results = results.filter((r): r is FPVector => r !== undefined);
+
+ return {
+ input: [
+ toVector(x, fp.scalarBuilder),
+ toVector(y, fp.scalarBuilder),
+ toVector(z, fp.scalarBuilder),
+ ],
+ expected: anyOf(...define_results),
+ };
+}
+
+/**
+ * @returns an array of Cases for `faceForward`
+ * @param kind what kind of floating point numbers being operated on
+ * @param xs array of inputs to try for the `x` param
+ * @param ys array of inputs to try for the `y` param
+ * @param zs array of inputs to try for the `z` param
+ * @param check what interval checking to apply
+ */
+function generateCases(
+ kind: FPKind,
+ xs: ROArrayArray,
+ ys: ROArrayArray,
+ zs: ROArrayArray,
+ check: IntervalFilter
+): Case[] {
+ // Cannot use `cartesianProduct` here due to heterogeneous param types
+ return cartesianProduct(xs, ys, zs)
+ .map(e => makeCase(kind, e[0], e[1], e[2], check))
+ .filter((c): c is Case => c !== undefined);
+}
+
+// Cases: [f32|f16]_vecN_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([2, 3, 4] as const).flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return generateCases(
+ trait,
+ FP[trait].sparseVectorRange(dim),
+ FP[trait].sparseVectorRange(dim),
+ FP[trait].sparseVectorRange(dim),
+ nonConst ? 'unfiltered' : 'finite'
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('faceForward', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts
index 767dbf35a894..c21541ab8839 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts
@@ -7,109 +7,15 @@ Returns e1 if dot(e2,e3) is negative, and -e1 otherwise.
`;
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
-import { ROArrayArray } from '../../../../../../common/util/types.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { anyOf } from '../../../../../util/compare.js';
-import { toVector, TypeF32, TypeF16, TypeVec } from '../../../../../util/conversion.js';
-import { FP, FPKind, FPVector } from '../../../../../util/floating_point.js';
-import { cartesianProduct } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
-import { allInputSources, Case, IntervalFilter, run } from '../../expression.js';
+import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js';
+import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './faceForward.cache.js';
export const g = makeTestGroup(GPUTest);
-// Using a bespoke implementation of make*Case and generate*Cases here
-// since faceForwardIntervals is the only builtin with the API signature
-// (vec, vec, vec) -> vec
-//
-// Additionally faceForward has significant complexities around it due to the
-// fact that `dot` is calculated in it s operation, but the result of dot isn't
-// used to calculate the builtin's result.
-
-/**
- * @returns a Case for `faceForward`
- * @param kind what kind of floating point numbers being operated on
- * @param x the `x` param for the case
- * @param y the `y` param for the case
- * @param z the `z` param for the case
- * @param check what interval checking to apply
- * */
-function makeCase(
- kind: FPKind,
- x: readonly number[],
- y: readonly number[],
- z: readonly number[],
- check: IntervalFilter
-): Case | undefined {
- const fp = FP[kind];
- x = x.map(fp.quantize);
- y = y.map(fp.quantize);
- z = z.map(fp.quantize);
-
- const results = FP[kind].faceForwardIntervals(x, y, z);
- if (check === 'finite' && results.some(r => r === undefined)) {
- return undefined;
- }
-
- // Stripping the undefined results, since undefined is used to signal that an OOB
- // could occur within the calculation that isn't reflected in the result
- // intervals.
- const define_results = results.filter((r): r is FPVector => r !== undefined);
-
- return {
- input: [
- toVector(x, fp.scalarBuilder),
- toVector(y, fp.scalarBuilder),
- toVector(z, fp.scalarBuilder),
- ],
- expected: anyOf(...define_results),
- };
-}
-
-/**
- * @returns an array of Cases for `faceForward`
- * @param kind what kind of floating point numbers being operated on
- * @param xs array of inputs to try for the `x` param
- * @param ys array of inputs to try for the `y` param
- * @param zs array of inputs to try for the `z` param
- * @param check what interval checking to apply
- */
-function generateCases(
- kind: FPKind,
- xs: ROArrayArray,
- ys: ROArrayArray,
- zs: ROArrayArray,
- check: IntervalFilter
-): Case[] {
- // Cannot use `cartesianProduct` here due to heterogeneous param types
- return cartesianProduct(xs, ys, zs)
- .map(e => makeCase(kind, e[0], e[1], e[2], check))
- .filter((c): c is Case => c !== undefined);
-}
-
-// Cases: [f32|f16]_vecN_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([2, 3, 4] as const).flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return generateCases(
- trait,
- FP[trait].sparseVectorRange(dim),
- FP[trait].sparseVectorRange(dim),
- FP[trait].sparseVectorRange(dim),
- nonConst ? 'unfiltered' : 'finite'
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('faceForward', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/floor.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/floor.cache.ts
new file mode 100644
index 000000000000..0af966cfd257
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/floor.cache.ts
@@ -0,0 +1,26 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+const kSmallMagnitudeTestValues = [0.1, 0.9, 1.0, 1.1, 1.9, -0.1, -0.9, -1.0, -1.1, -1.9];
+
+// See https://github.com/gpuweb/cts/issues/2766 for details
+const kIssue2766Value = {
+ abstract: 0x8000_0000_0000_0000,
+ f32: 0x8000_0000,
+ f16: 0x8000,
+};
+
+// Cases: [f32|f16|abstract]
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [...kSmallMagnitudeTestValues, kIssue2766Value[trait], ...FP[trait].scalarRange()],
+ 'unfiltered',
+ FP[trait].floorInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('floor', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/floor.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/floor.spec.ts
index d756042a9e86..08a29ed3e5f4 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/floor.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/floor.spec.ts
@@ -9,39 +9,14 @@ Returns the floor of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16, TypeAbstractFloat } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './floor.cache.js';
export const g = makeTestGroup(GPUTest);
-const kSmallMagnitudeTestValues = [0.1, 0.9, 1.0, 1.1, 1.9, -0.1, -0.9, -1.0, -1.1, -1.9];
-
-// See https://github.com/gpuweb/cts/issues/2766 for details
-const kIssue2766Value = {
- abstract: 0x8000_0000_0000_0000,
- f32: 0x8000_0000,
- f16: 0x8000,
-};
-
-// Cases: [f32|f16|abstract]
-const cases = (['f32', 'f16', 'abstract'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [...kSmallMagnitudeTestValues, kIssue2766Value[trait], ...FP[trait].scalarRange()],
- 'unfiltered',
- FP[trait].floorInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('floor', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/fma.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/fma.cache.ts
new file mode 100644
index 000000000000..0efa57f39c73
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/fma.cache.ts
@@ -0,0 +1,25 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]_[non_]const
+// abstract_non_const is empty and not used
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ if (trait === 'abstract' && nonConst) {
+ return [];
+ }
+ return FP[trait].generateScalarTripleToIntervalCases(
+ FP[trait].sparseScalarRange(),
+ FP[trait].sparseScalarRange(),
+ FP[trait].sparseScalarRange(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].fmaInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('fma', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/fma.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/fma.spec.ts
index 6a275afad6f5..39360cb5bc51 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/fma.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/fma.spec.ts
@@ -9,38 +9,14 @@ Returns e1 * e2 + e3. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16, TypeAbstractFloat } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './fma.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16|abstract]_[non_]const
-// abstract_non_const is empty and not used
-const cases = (['f32', 'f16', 'abstract'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- if (trait === 'abstract' && nonConst) {
- return [];
- }
- return FP[trait].generateScalarTripleToIntervalCases(
- FP[trait].sparseScalarRange(),
- FP[trait].sparseScalarRange(),
- FP[trait].sparseScalarRange(),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].fmaInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('fma', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/fract.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/fract.cache.ts
new file mode 100644
index 000000000000..56fa3f661f1f
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/fract.cache.ts
@@ -0,0 +1,45 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+const kCommonValues = [
+ 0.5, // 0.5 -> 0.5
+ 0.9, // ~0.9 -> ~0.9
+ 1, // 1 -> 0
+ 2, // 2 -> 0
+ 1.11, // ~1.11 -> ~0.11
+ -0.1, // ~-0.1 -> ~0.9
+ -0.5, // -0.5 -> 0.5
+ -0.9, // ~-0.9 -> ~0.1
+ -1, // -1 -> 0
+ -2, // -2 -> 0
+ -1.11, // ~-1.11 -> ~0.89
+];
+
+const kTraitSpecificValues = {
+ f32: [
+ 10.0001, // ~10.0001 -> ~0.0001
+ -10.0001, // -10.0001 -> ~0.9999
+ 0x8000_0000, // https://github.com/gpuweb/cts/issues/2766
+ ],
+ f16: [
+ 10.0078125, // 10.0078125 -> 0.0078125
+ -10.0078125, // -10.0078125 -> 0.9921875
+ 658.5, // 658.5 -> 0.5
+ 0x8000, // https://github.com/gpuweb/cts/issues/2766
+ ],
+};
+
+// Cases: [f32|f16]
+const cases = (['f32', 'f16'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [...kCommonValues, ...kTraitSpecificValues[trait], ...FP[trait].scalarRange()],
+ 'unfiltered',
+ FP[trait].fractInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('fract', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/fract.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/fract.spec.ts
index 9f412129733a..df9e1845273e 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/fract.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/fract.spec.ts
@@ -10,58 +10,14 @@ Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './fract.cache.js';
export const g = makeTestGroup(GPUTest);
-const kCommonValues = [
- 0.5, // 0.5 -> 0.5
- 0.9, // ~0.9 -> ~0.9
- 1, // 1 -> 0
- 2, // 2 -> 0
- 1.11, // ~1.11 -> ~0.11
- -0.1, // ~-0.1 -> ~0.9
- -0.5, // -0.5 -> 0.5
- -0.9, // ~-0.9 -> ~0.1
- -1, // -1 -> 0
- -2, // -2 -> 0
- -1.11, // ~-1.11 -> ~0.89
-];
-
-const kTraitSpecificValues = {
- f32: [
- 10.0001, // ~10.0001 -> ~0.0001
- -10.0001, // -10.0001 -> ~0.9999
- 0x8000_0000, // https://github.com/gpuweb/cts/issues/2766
- ],
- f16: [
- 10.0078125, // 10.0078125 -> 0.0078125
- -10.0078125, // -10.0078125 -> 0.9921875
- 658.5, // 658.5 -> 0.5
- 0x8000, // https://github.com/gpuweb/cts/issues/2766
- ],
-};
-
-// Cases: [f32|f16]
-const cases = (['f32', 'f16'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [...kCommonValues, ...kTraitSpecificValues[trait], ...FP[trait].scalarRange()],
- 'unfiltered',
- FP[trait].fractInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('fract', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/frexp.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/frexp.cache.ts
new file mode 100644
index 000000000000..7c107eb729a7
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/frexp.cache.ts
@@ -0,0 +1,95 @@
+import { skipUndefined } from '../../../../../util/compare.js';
+import { Scalar, Vector, i32, toVector } from '../../../../../util/conversion.js';
+import { FP } from '../../../../../util/floating_point.js';
+import { frexp } from '../../../../../util/math.js';
+import { Case } from '../../case.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+/* @returns a fract Case for a given scalar or vector input */
+function makeCaseFract(v: number | readonly number[], trait: 'f32' | 'f16'): Case {
+ const fp = FP[trait];
+ let toInput: (n: readonly number[]) => Scalar | Vector;
+ let toOutput: (n: readonly number[]) => Scalar | Vector;
+ if (v instanceof Array) {
+ // Input is vector
+ toInput = (n: readonly number[]) => toVector(n, fp.scalarBuilder);
+ toOutput = (n: readonly number[]) => toVector(n, fp.scalarBuilder);
+ } else {
+ // Input is scalar, also wrap it in an array.
+ v = [v];
+ toInput = (n: readonly number[]) => fp.scalarBuilder(n[0]);
+ toOutput = (n: readonly number[]) => fp.scalarBuilder(n[0]);
+ }
+
+ v = v.map(fp.quantize);
+ if (v.some(e => e !== 0 && fp.isSubnormal(e))) {
+ return { input: toInput(v), expected: skipUndefined(undefined) };
+ }
+
+ const fs = v.map(e => {
+ return frexp(e, trait).fract;
+ });
+
+ return { input: toInput(v), expected: toOutput(fs) };
+}
+
+/* @returns an exp Case for a given scalar or vector input */
+function makeCaseExp(v: number | readonly number[], trait: 'f32' | 'f16'): Case {
+ const fp = FP[trait];
+ let toInput: (n: readonly number[]) => Scalar | Vector;
+ let toOutput: (n: readonly number[]) => Scalar | Vector;
+ if (v instanceof Array) {
+ // Input is vector
+ toInput = (n: readonly number[]) => toVector(n, fp.scalarBuilder);
+ toOutput = (n: readonly number[]) => toVector(n, i32);
+ } else {
+ // Input is scalar, also wrap it in an array.
+ v = [v];
+ toInput = (n: readonly number[]) => fp.scalarBuilder(n[0]);
+ toOutput = (n: readonly number[]) => i32(n[0]);
+ }
+
+ v = v.map(fp.quantize);
+ if (v.some(e => e !== 0 && fp.isSubnormal(e))) {
+ return { input: toInput(v), expected: skipUndefined(undefined) };
+ }
+
+ const fs = v.map(e => {
+ return frexp(e, trait).exp;
+ });
+
+ return { input: toInput(v), expected: toOutput(fs) };
+}
+
+// Cases: [f32|f16]_vecN_[exp|whole]
+const vec_cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([2, 3, 4] as const).flatMap(dim =>
+ (['exp', 'fract'] as const).map(portion => ({
+ [`${trait}_vec${dim}_${portion}`]: () => {
+ return FP[trait]
+ .vectorRange(dim)
+ .map(v => (portion === 'exp' ? makeCaseExp(v, trait) : makeCaseFract(v, trait)));
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: [f32|f16]_[exp|whole]
+const scalar_cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ (['exp', 'fract'] as const).map(portion => ({
+ [`${trait}_${portion}`]: () => {
+ return FP[trait]
+ .scalarRange()
+ .map(v => (portion === 'exp' ? makeCaseExp(v, trait) : makeCaseFract(v, trait)));
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('frexp', {
+ ...scalar_cases,
+ ...vec_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/frexp.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/frexp.spec.ts
index 32565ef23667..663e345f499a 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/frexp.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/frexp.spec.ts
@@ -15,27 +15,10 @@ The magnitude of the significand is in the range of [0.5, 1.0) or 0.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { skipUndefined } from '../../../../../util/compare.js';
-import {
- i32,
- Scalar,
- toVector,
- TypeF32,
- TypeF16,
- TypeI32,
- TypeVec,
- Vector,
-} from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { frexp } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
-import {
- allInputSources,
- basicExpressionBuilder,
- Case,
- run,
- ShaderBuilder,
-} from '../../expression.js';
+import { TypeF16, TypeF32, TypeI32, TypeVec } from '../../../../../util/conversion.js';
+import { ShaderBuilder, allInputSources, basicExpressionBuilder, run } from '../../expression.js';
+
+import { d } from './frexp.cache.js';
export const g = makeTestGroup(GPUTest);
@@ -48,96 +31,6 @@ function fractBuilder(): ShaderBuilder {
function expBuilder(): ShaderBuilder {
return basicExpressionBuilder(value => `frexp(${value}).exp`);
}
-
-/* @returns a fract Case for a given scalar or vector input */
-function makeCaseFract(v: number | readonly number[], trait: 'f32' | 'f16'): Case {
- const fp = FP[trait];
- let toInput: (n: readonly number[]) => Scalar | Vector;
- let toOutput: (n: readonly number[]) => Scalar | Vector;
- if (v instanceof Array) {
- // Input is vector
- toInput = (n: readonly number[]) => toVector(n, fp.scalarBuilder);
- toOutput = (n: readonly number[]) => toVector(n, fp.scalarBuilder);
- } else {
- // Input is scalar, also wrap it in an array.
- v = [v];
- toInput = (n: readonly number[]) => fp.scalarBuilder(n[0]);
- toOutput = (n: readonly number[]) => fp.scalarBuilder(n[0]);
- }
-
- v = v.map(fp.quantize);
- if (v.some(e => e !== 0 && fp.isSubnormal(e))) {
- return { input: toInput(v), expected: skipUndefined(undefined) };
- }
-
- const fs = v.map(e => {
- return frexp(e, trait).fract;
- });
-
- return { input: toInput(v), expected: toOutput(fs) };
-}
-
-/* @returns an exp Case for a given scalar or vector input */
-function makeCaseExp(v: number | readonly number[], trait: 'f32' | 'f16'): Case {
- const fp = FP[trait];
- let toInput: (n: readonly number[]) => Scalar | Vector;
- let toOutput: (n: readonly number[]) => Scalar | Vector;
- if (v instanceof Array) {
- // Input is vector
- toInput = (n: readonly number[]) => toVector(n, fp.scalarBuilder);
- toOutput = (n: readonly number[]) => toVector(n, i32);
- } else {
- // Input is scalar, also wrap it in an array.
- v = [v];
- toInput = (n: readonly number[]) => fp.scalarBuilder(n[0]);
- toOutput = (n: readonly number[]) => i32(n[0]);
- }
-
- v = v.map(fp.quantize);
- if (v.some(e => e !== 0 && fp.isSubnormal(e))) {
- return { input: toInput(v), expected: skipUndefined(undefined) };
- }
-
- const fs = v.map(e => {
- return frexp(e, trait).exp;
- });
-
- return { input: toInput(v), expected: toOutput(fs) };
-}
-
-// Cases: [f32|f16]_vecN_[exp|whole]
-const vec_cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([2, 3, 4] as const).flatMap(dim =>
- (['exp', 'fract'] as const).map(portion => ({
- [`${trait}_vec${dim}_${portion}`]: () => {
- return FP[trait]
- .vectorRange(dim)
- .map(v => (portion === 'exp' ? makeCaseExp(v, trait) : makeCaseFract(v, trait)));
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: [f32|f16]_[exp|whole]
-const scalar_cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- (['exp', 'fract'] as const).map(portion => ({
- [`${trait}_${portion}`]: () => {
- return FP[trait]
- .scalarRange()
- .map(v => (portion === 'exp' ? makeCaseExp(v, trait) : makeCaseFract(v, trait)));
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('frexp', {
- ...scalar_cases,
- ...vec_cases,
-});
-
g.test('f32_fract')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(
diff --git a/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.cache.ts
new file mode 100644
index 000000000000..3ad58d5fc12c
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.cache.ts
@@ -0,0 +1,31 @@
+import { kValue } from '../../../../../util/constants.js';
+import { FP } from '../../../../../util/floating_point.js';
+import { biasedRange, linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+export const d = makeCaseCache('inverseSqrt', {
+ f32: () => {
+ return FP.f32.generateScalarToIntervalCases(
+ [
+ // 0 < x <= 1 linearly spread
+ ...linearRange(kValue.f32.positive.min, 1, 100),
+ // 1 <= x < 2^32, biased towards 1
+ ...biasedRange(1, 2 ** 32, 1000),
+ ],
+ 'unfiltered',
+ FP.f32.inverseSqrtInterval
+ );
+ },
+ f16: () => {
+ return FP.f16.generateScalarToIntervalCases(
+ [
+ // 0 < x <= 1 linearly spread
+ ...linearRange(kValue.f16.positive.min, 1, 100),
+ // 1 <= x < 2^15, biased towards 1
+ ...biasedRange(1, 2 ** 15, 1000),
+ ],
+ 'unfiltered',
+ FP.f16.inverseSqrtInterval
+ );
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.spec.ts
index 3e83816387d8..fb5248ec8ad6 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.spec.ts
@@ -9,44 +9,14 @@ Returns the reciprocal of sqrt(e). Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { kValue } from '../../../../../util/constants.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { biasedRange, linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './inversesqrt.cache.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('inverseSqrt', {
- f32: () => {
- return FP.f32.generateScalarToIntervalCases(
- [
- // 0 < x <= 1 linearly spread
- ...linearRange(kValue.f32.positive.min, 1, 100),
- // 1 <= x < 2^32, biased towards 1
- ...biasedRange(1, 2 ** 32, 1000),
- ],
- 'unfiltered',
- FP.f32.inverseSqrtInterval
- );
- },
- f16: () => {
- return FP.f16.generateScalarToIntervalCases(
- [
- // 0 < x <= 1 linearly spread
- ...linearRange(kValue.f16.positive.min, 1, 100),
- // 1 <= x < 2^15, biased towards 1
- ...biasedRange(1, 2 ** 15, 1000),
- ],
- 'unfiltered',
- FP.f16.inverseSqrtInterval
- );
- },
-});
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/ldexp.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/ldexp.cache.ts
new file mode 100644
index 000000000000..edee0a7f3d89
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/ldexp.cache.ts
@@ -0,0 +1,61 @@
+import { assert } from '../../../../../../common/util/util.js';
+import { anyOf } from '../../../../../util/compare.js';
+import { i32 } from '../../../../../util/conversion.js';
+import { FP } from '../../../../../util/floating_point.js';
+import { biasedRange, quantizeToI32, sparseI32Range } from '../../../../../util/math.js';
+import { Case } from '../../case.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+const bias = {
+ f32: 127,
+ f16: 15,
+} as const;
+
+// ldexpInterval's return interval doesn't cover the flush-to-zero cases when e2 + bias <= 0, thus
+// special examination is required.
+// See the comment block on ldexpInterval for more details
+// e2 is an integer (i32) while e1 is float.
+const makeCase = (trait: 'f32' | 'f16', e1: number, e2: number): Case => {
+ const FPTrait = FP[trait];
+ e1 = FPTrait.quantize(e1);
+ // e2 should be in i32 range for the convinience.
+ assert(-2147483648 <= e2 && e2 <= 2147483647, 'e2 should be in i32 range');
+ e2 = quantizeToI32(e2);
+
+ const expected = FPTrait.ldexpInterval(e1, e2);
+
+ // Result may be zero if e2 + bias <= 0
+ if (e2 + bias[trait] <= 0) {
+ return {
+ input: [FPTrait.scalarBuilder(e1), i32(e2)],
+ expected: anyOf(expected, FPTrait.constants().zeroInterval),
+ };
+ }
+
+ return { input: [FPTrait.scalarBuilder(e1), i32(e2)], expected };
+};
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ if (nonConst) {
+ return FP[trait]
+ .sparseScalarRange()
+ .flatMap(e1 => sparseI32Range().map(e2 => makeCase(trait, e1, e2)));
+ }
+ // const
+ return FP[trait]
+ .sparseScalarRange()
+ .flatMap(e1 =>
+ biasedRange(-bias[trait] - 10, bias[trait] + 1, 10).flatMap(e2 =>
+ FP[trait].isFinite(e1 * 2 ** quantizeToI32(e2)) ? makeCase(trait, e1, e2) : []
+ )
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('ldexp', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/ldexp.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/ldexp.spec.ts
index 2eec0c8ead5d..e2eba8232d43 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/ldexp.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/ldexp.spec.ts
@@ -13,73 +13,15 @@ Returns e1 * 2^e2. Component-wise when T is a vector.
`;
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
-import { assert } from '../../../../../../common/util/util.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { anyOf } from '../../../../../util/compare.js';
-import { i32, TypeF32, TypeF16, TypeI32 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { biasedRange, quantizeToI32, sparseI32Range } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
-import { allInputSources, Case, run } from '../../expression.js';
+import { TypeF16, TypeF32, TypeI32 } from '../../../../../util/conversion.js';
+import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './ldexp.cache.js';
export const g = makeTestGroup(GPUTest);
-const bias = {
- f32: 127,
- f16: 15,
-} as const;
-
-// ldexpInterval's return interval doesn't cover the flush-to-zero cases when e2 + bias <= 0, thus
-// special examination is required.
-// See the comment block on ldexpInterval for more details
-// e2 is an integer (i32) while e1 is float.
-const makeCase = (trait: 'f32' | 'f16', e1: number, e2: number): Case => {
- const FPTrait = FP[trait];
- e1 = FPTrait.quantize(e1);
- // e2 should be in i32 range for the convinience.
- assert(-2147483648 <= e2 && e2 <= 2147483647, 'e2 should be in i32 range');
- e2 = quantizeToI32(e2);
-
- const expected = FPTrait.ldexpInterval(e1, e2);
-
- // Result may be zero if e2 + bias <= 0
- if (e2 + bias[trait] <= 0) {
- return {
- input: [FPTrait.scalarBuilder(e1), i32(e2)],
- expected: anyOf(expected, FPTrait.constants().zeroInterval),
- };
- }
-
- return { input: [FPTrait.scalarBuilder(e1), i32(e2)], expected };
-};
-
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- if (nonConst) {
- return FP[trait]
- .sparseScalarRange()
- .flatMap(e1 => sparseI32Range().map(e2 => makeCase(trait, e1, e2)));
- }
- // const
- return FP[trait]
- .sparseScalarRange()
- .flatMap(e1 =>
- biasedRange(-bias[trait] - 10, bias[trait] + 1, 10).flatMap(e2 =>
- FP[trait].isFinite(e1 * 2 ** quantizeToI32(e2)) ? makeCase(trait, e1, e2) : []
- )
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('ldexp', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(
diff --git a/src/webgpu/shader/execution/expression/call/builtin/length.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/length.cache.ts
new file mode 100644
index 000000000000..f194352ff7f5
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/length.cache.ts
@@ -0,0 +1,37 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const scalar_cases = (['f32', 'f16'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ 'unfiltered',
+ FP[trait].lengthInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: [f32|f16]_vecN_[non_]const
+const vec_cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([2, 3, 4] as const).flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateVectorToIntervalCases(
+ FP[trait].vectorRange(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].lengthInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('length', {
+ ...scalar_cases,
+ ...vec_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/length.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/length.spec.ts
index 82028dfdf98f..e91d5dcdafe5 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/length.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/length.spec.ts
@@ -9,50 +9,14 @@ Returns the length of e (e.g. abs(e) if T is a scalar, or sqrt(e[0]^2 + e[1]^2 +
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './length.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const scalar_cases = (['f32', 'f16'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- 'unfiltered',
- FP[trait].lengthInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: [f32|f16]_vecN_[non_]const
-const vec_cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([2, 3, 4] as const).flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateVectorToIntervalCases(
- FP[trait].vectorRange(dim),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].lengthInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('length', {
- ...scalar_cases,
- ...vec_cases,
-});
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#numeric-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/log.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/log.cache.ts
new file mode 100644
index 000000000000..11d900f7dc53
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/log.cache.ts
@@ -0,0 +1,26 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { biasedRange, linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// log's accuracy is defined in three regions { [0, 0.5), [0.5, 2.0], (2.0, +∞] }
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [
+ ...linearRange(FP[trait].constants().positive.min, 0.5, 20),
+ ...linearRange(0.5, 2.0, 20),
+ ...biasedRange(2.0, 2 ** 32, 1000),
+ ...FP[trait].scalarRange(),
+ ],
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].logInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('log', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/log.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/log.spec.ts
index 19e367611f49..387705320ff9 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/log.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/log.spec.ts
@@ -9,39 +9,14 @@ Returns the natural logarithm of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { biasedRange, linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './log.cache.js';
export const g = makeTestGroup(GPUTest);
-// log's accuracy is defined in three regions { [0, 0.5), [0.5, 2.0], (2.0, +∞] }
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [
- ...linearRange(FP[trait].constants().positive.min, 0.5, 20),
- ...linearRange(0.5, 2.0, 20),
- ...biasedRange(2.0, 2 ** 32, 1000),
- ...FP[trait].scalarRange(),
- ],
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].logInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('log', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/log2.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/log2.cache.ts
new file mode 100644
index 000000000000..310ae2b85cae
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/log2.cache.ts
@@ -0,0 +1,26 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { biasedRange, linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// log2's accuracy is defined in three regions { [0, 0.5), [0.5, 2.0], (2.0, +∞] }
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [
+ ...linearRange(FP[trait].constants().positive.min, 0.5, 20),
+ ...linearRange(0.5, 2.0, 20),
+ ...biasedRange(2.0, 2 ** 32, 1000),
+ ...FP[trait].scalarRange(),
+ ],
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].log2Interval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('log2', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/log2.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/log2.spec.ts
index 2850a6410033..86a38a60246a 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/log2.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/log2.spec.ts
@@ -9,39 +9,14 @@ Returns the base-2 logarithm of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { biasedRange, linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './log2.cache.js';
export const g = makeTestGroup(GPUTest);
-// log2's accuracy is defined in three regions { [0, 0.5), [0.5, 2.0], (2.0, +∞] }
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [
- ...linearRange(FP[trait].constants().positive.min, 0.5, 20),
- ...linearRange(0.5, 2.0, 20),
- ...biasedRange(2.0, 2 ** 32, 1000),
- ...FP[trait].scalarRange(),
- ],
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].log2Interval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('log2', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/max.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/max.cache.ts
new file mode 100644
index 000000000000..7566d9342fa5
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/max.cache.ts
@@ -0,0 +1,18 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarPairToIntervalCases(
+ FP[trait].scalarRange(),
+ FP[trait].scalarRange(),
+ 'unfiltered',
+ FP[trait].maxInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('max', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/max.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/max.spec.ts
index 7a7d199f4eb8..a596c3f12486 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/max.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/max.spec.ts
@@ -19,19 +19,19 @@ Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import {
- i32,
- TypeF32,
+ TypeAbstractFloat,
TypeF16,
+ TypeF32,
TypeI32,
TypeU32,
+ i32,
u32,
- TypeAbstractFloat,
} from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
-import { allInputSources, Case, onlyConstInputSource, run } from '../../expression.js';
+import { Case } from '../../case.js';
+import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './max.cache.js';
/** Generate set of max test cases from list of interesting values */
function generateTestCases(
@@ -49,22 +49,6 @@ function generateTestCases(
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16|abstract]
-const cases = (['f32', 'f16', 'abstract'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarPairToIntervalCases(
- FP[trait].scalarRange(),
- FP[trait].scalarRange(),
- 'unfiltered',
- FP[trait].maxInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('max', cases);
-
g.test('abstract_int')
.specURL('https://www.w3.org/TR/WGSL/#integer-builtin-functions')
.desc(`abstract int tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/min.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/min.cache.ts
new file mode 100644
index 000000000000..83c986a392ed
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/min.cache.ts
@@ -0,0 +1,18 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarPairToIntervalCases(
+ FP[trait].scalarRange(),
+ FP[trait].scalarRange(),
+ 'unfiltered',
+ FP[trait].minInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('min', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/min.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/min.spec.ts
index 68fb5be8d2d6..a9ada22da702 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/min.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/min.spec.ts
@@ -18,19 +18,19 @@ Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import {
- i32,
- TypeF32,
+ TypeAbstractFloat,
TypeF16,
+ TypeF32,
TypeI32,
TypeU32,
+ i32,
u32,
- TypeAbstractFloat,
} from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
-import { allInputSources, Case, onlyConstInputSource, run } from '../../expression.js';
+import { Case } from '../../case.js';
+import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './min.cache.js';
export const g = makeTestGroup(GPUTest);
@@ -48,22 +48,6 @@ function generateTestCases(
return cases;
}
-// Cases: [f32|f16|abstract]
-const cases = (['f32', 'f16', 'abstract'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarPairToIntervalCases(
- FP[trait].scalarRange(),
- FP[trait].scalarRange(),
- 'unfiltered',
- FP[trait].minInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('min', cases);
-
g.test('abstract_int')
.specURL('https://www.w3.org/TR/WGSL/#integer-builtin-functions')
.desc(`abstract int tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/mix.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/mix.cache.ts
new file mode 100644
index 000000000000..12176f87d4cf
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/mix.cache.ts
@@ -0,0 +1,43 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const scalar_cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarTripleToIntervalCases(
+ FP[trait].sparseScalarRange(),
+ FP[trait].sparseScalarRange(),
+ FP[trait].sparseScalarRange(),
+ nonConst ? 'unfiltered' : 'finite',
+ ...FP[trait].mixIntervals
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: [f32|f16]_vecN_scalar_[non_]const
+const vec_scalar_cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([2, 3, 4] as const).flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateVectorPairScalarToVectorComponentWiseCase(
+ FP[trait].sparseVectorRange(dim),
+ FP[trait].sparseVectorRange(dim),
+ FP[trait].sparseScalarRange(),
+ nonConst ? 'unfiltered' : 'finite',
+ ...FP[trait].mixIntervals
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('mix', {
+ ...scalar_cases,
+ ...vec_scalar_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/mix.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/mix.spec.ts
index 80b28508ecef..c4d443698746 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/mix.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/mix.spec.ts
@@ -16,56 +16,14 @@ Same as mix(e1,e2,T2(e3)).
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeVec, TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './mix.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const scalar_cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarTripleToIntervalCases(
- FP[trait].sparseScalarRange(),
- FP[trait].sparseScalarRange(),
- FP[trait].sparseScalarRange(),
- nonConst ? 'unfiltered' : 'finite',
- ...FP[trait].mixIntervals
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: [f32|f16]_vecN_scalar_[non_]const
-const vec_scalar_cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([2, 3, 4] as const).flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_vec${dim}_scalar_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateVectorPairScalarToVectorComponentWiseCase(
- FP[trait].sparseVectorRange(dim),
- FP[trait].sparseVectorRange(dim),
- FP[trait].sparseScalarRange(),
- nonConst ? 'unfiltered' : 'finite',
- ...FP[trait].mixIntervals
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('mix', {
- ...scalar_cases,
- ...vec_scalar_cases,
-});
-
g.test('abstract_float_matching')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract_float test with matching third param`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/modf.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/modf.cache.ts
new file mode 100644
index 000000000000..1a76de56bbae
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/modf.cache.ts
@@ -0,0 +1,75 @@
+import { toVector } from '../../../../../util/conversion.js';
+import { FP, FPKind } from '../../../../../util/floating_point.js';
+import { Case } from '../../case.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+/** @returns a fract Case for a scalar vector input */
+function makeScalarCaseFract(kind: FPKind, n: number): Case {
+ const fp = FP[kind];
+ n = fp.quantize(n);
+ const result = fp.modfInterval(n).fract;
+
+ return { input: fp.scalarBuilder(n), expected: result };
+}
+
+/** @returns a whole Case for a scalar vector input */
+function makeScalarCaseWhole(kind: FPKind, n: number): Case {
+ const fp = FP[kind];
+ n = fp.quantize(n);
+ const result = fp.modfInterval(n).whole;
+
+ return { input: fp.scalarBuilder(n), expected: result };
+}
+
+/** @returns a fract Case for a given vector input */
+function makeVectorCaseFract(kind: FPKind, v: readonly number[]): Case {
+ const fp = FP[kind];
+ v = v.map(fp.quantize);
+ const fs = v.map(e => {
+ return fp.modfInterval(e).fract;
+ });
+
+ return { input: toVector(v, fp.scalarBuilder), expected: fs };
+}
+
+/** @returns a whole Case for a given vector input */
+function makeVectorCaseWhole(kind: FPKind, v: readonly number[]): Case {
+ const fp = FP[kind];
+ v = v.map(fp.quantize);
+ const ws = v.map(e => {
+ return fp.modfInterval(e).whole;
+ });
+
+ return { input: toVector(v, fp.scalarBuilder), expected: ws };
+}
+
+// Cases: [f32|f16|abstract]_[fract|whole]
+const scalar_cases = (['f32', 'f16', 'abstract'] as const)
+ .flatMap(kind =>
+ (['whole', 'fract'] as const).map(portion => ({
+ [`${kind}_${portion}`]: () => {
+ const makeCase = portion === 'whole' ? makeScalarCaseWhole : makeScalarCaseFract;
+ return FP[kind].scalarRange().map(makeCase.bind(null, kind));
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+// Cases: [f32|f16|abstract]_vecN_[fract|whole]
+const vec_cases = (['f32', 'f16', 'abstract'] as const)
+ .flatMap(kind =>
+ ([2, 3, 4] as const).flatMap(n =>
+ (['whole', 'fract'] as const).map(portion => ({
+ [`${kind}_vec${n}_${portion}`]: () => {
+ const makeCase = portion === 'whole' ? makeVectorCaseWhole : makeVectorCaseFract;
+ return FP[kind].vectorRange(n).map(makeCase.bind(null, kind));
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('modf', {
+ ...scalar_cases,
+ ...vec_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/modf.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/modf.spec.ts
index d6b82957b202..3e12d4f8696d 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/modf.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/modf.spec.ts
@@ -18,25 +18,18 @@ Returns the result_struct for the given type.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import {
- toVector,
- TypeAbstractFloat,
- TypeF16,
- TypeF32,
- TypeVec,
-} from '../../../../../util/conversion.js';
-import { FP, FPKind } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeAbstractFloat, TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js';
import {
abstractFloatShaderBuilder,
allInputSources,
basicExpressionBuilder,
- Case,
onlyConstInputSource,
run,
ShaderBuilder,
} from '../../expression.js';
+import { d } from './modf.cache.js';
+
export const g = makeTestGroup(GPUTest);
/** @returns an ShaderBuilder that evaluates modf and returns .whole from the result structure */
@@ -59,77 +52,6 @@ function abstractFractBuilder(): ShaderBuilder {
return abstractFloatShaderBuilder(value => `modf(${value}).fract`);
}
-/** @returns a fract Case for a scalar vector input */
-function makeScalarCaseFract(kind: FPKind, n: number): Case {
- const fp = FP[kind];
- n = fp.quantize(n);
- const result = fp.modfInterval(n).fract;
-
- return { input: fp.scalarBuilder(n), expected: result };
-}
-
-/** @returns a whole Case for a scalar vector input */
-function makeScalarCaseWhole(kind: FPKind, n: number): Case {
- const fp = FP[kind];
- n = fp.quantize(n);
- const result = fp.modfInterval(n).whole;
-
- return { input: fp.scalarBuilder(n), expected: result };
-}
-
-/** @returns a fract Case for a given vector input */
-function makeVectorCaseFract(kind: FPKind, v: readonly number[]): Case {
- const fp = FP[kind];
- v = v.map(fp.quantize);
- const fs = v.map(e => {
- return fp.modfInterval(e).fract;
- });
-
- return { input: toVector(v, fp.scalarBuilder), expected: fs };
-}
-
-/** @returns a whole Case for a given vector input */
-function makeVectorCaseWhole(kind: FPKind, v: readonly number[]): Case {
- const fp = FP[kind];
- v = v.map(fp.quantize);
- const ws = v.map(e => {
- return fp.modfInterval(e).whole;
- });
-
- return { input: toVector(v, fp.scalarBuilder), expected: ws };
-}
-
-// Cases: [f32|f16|abstract]_[fract|whole]
-const scalar_cases = (['f32', 'f16', 'abstract'] as const)
- .flatMap(kind =>
- (['whole', 'fract'] as const).map(portion => ({
- [`${kind}_${portion}`]: () => {
- const makeCase = portion === 'whole' ? makeScalarCaseWhole : makeScalarCaseFract;
- return FP[kind].scalarRange().map(makeCase.bind(null, kind));
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-// Cases: [f32|f16|abstract]_vecN_[fract|whole]
-const vec_cases = (['f32', 'f16', 'abstract'] as const)
- .flatMap(kind =>
- ([2, 3, 4] as const).flatMap(n =>
- (['whole', 'fract'] as const).map(portion => ({
- [`${kind}_vec${n}_${portion}`]: () => {
- const makeCase = portion === 'whole' ? makeVectorCaseWhole : makeVectorCaseFract;
- return FP[kind].vectorRange(n).map(makeCase.bind(null, kind));
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('modf', {
- ...scalar_cases,
- ...vec_cases,
-});
-
g.test('f32_fract')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(
diff --git a/src/webgpu/shader/execution/expression/call/builtin/normalize.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/normalize.cache.ts
new file mode 100644
index 000000000000..41c87b2fb93e
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/normalize.cache.ts
@@ -0,0 +1,21 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_vecN_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([2, 3, 4] as const).flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateVectorToVectorCases(
+ FP[trait].vectorRange(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].normalizeInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('normalize', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/normalize.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/normalize.spec.ts
index b9d1414f928d..4820f5884d69 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/normalize.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/normalize.spec.ts
@@ -8,34 +8,14 @@ Returns a unit vector in the same direction as e.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './normalize.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_vecN_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([2, 3, 4] as const).flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateVectorToVectorCases(
- FP[trait].vectorRange(dim),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].normalizeInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('normalize', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.cache.ts
new file mode 100644
index 000000000000..9cd7824cd978
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.cache.ts
@@ -0,0 +1,55 @@
+import { anyOf, skipUndefined } from '../../../../../util/compare.js';
+import { f32, pack2x16float, u32, vec2 } from '../../../../../util/conversion.js';
+import { cartesianProduct, quantizeToF32, scalarF32Range } from '../../../../../util/math.js';
+import { Case } from '../../case.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// pack2x16float has somewhat unusual behaviour, specifically around how it is
+// supposed to behave when values go OOB and when they are considered to have
+// gone OOB, so has its own bespoke implementation.
+
+/**
+ * @returns a Case for `pack2x16float`
+ * @param param0 first param for the case
+ * @param param1 second param for the case
+ * @param filter_undefined should inputs that cause an undefined expectation be
+ * filtered out, needed for const-eval
+ */
+function makeCase(param0: number, param1: number, filter_undefined: boolean): Case | undefined {
+ param0 = quantizeToF32(param0);
+ param1 = quantizeToF32(param1);
+
+ const results = pack2x16float(param0, param1);
+ if (filter_undefined && results.some(r => r === undefined)) {
+ return undefined;
+ }
+
+ return {
+ input: [vec2(f32(param0), f32(param1))],
+ expected: anyOf(
+ ...results.map(r => (r === undefined ? skipUndefined(undefined) : skipUndefined(u32(r))))
+ ),
+ };
+}
+
+/**
+ * @returns an array of Cases for `pack2x16float`
+ * @param param0s array of inputs to try for the first param
+ * @param param1s array of inputs to try for the second param
+ * @param filter_undefined should inputs that cause an undefined expectation be
+ * filtered out, needed for const-eval
+ */
+function generateCases(param0s: number[], param1s: number[], filter_undefined: boolean): Case[] {
+ return cartesianProduct(param0s, param1s)
+ .map(e => makeCase(e[0], e[1], filter_undefined))
+ .filter((c): c is Case => c !== undefined);
+}
+
+export const d = makeCaseCache('pack2x16float', {
+ f32_const: () => {
+ return generateCases(scalarF32Range(), scalarF32Range(), true);
+ },
+ f32_non_const: () => {
+ return generateCases(scalarF32Range(), scalarF32Range(), false);
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.spec.ts
index a0716038082f..efa4041259eb 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.spec.ts
@@ -6,74 +6,14 @@ which is then placed in bits 16 × i through 16 × i + 15 of the result.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { anyOf, skipUndefined } from '../../../../../util/compare.js';
-import {
- f32,
- pack2x16float,
- TypeF32,
- TypeU32,
- TypeVec,
- u32,
- vec2,
-} from '../../../../../util/conversion.js';
-import { cartesianProduct, scalarF32Range, quantizeToF32 } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
-import { allInputSources, Case, run } from '../../expression.js';
+import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js';
+import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './pack2x16float.cache.js';
export const g = makeTestGroup(GPUTest);
-// pack2x16float has somewhat unusual behaviour, specifically around how it is
-// supposed to behave when values go OOB and when they are considered to have
-// gone OOB, so has its own bespoke implementation.
-
-/**
- * @returns a Case for `pack2x16float`
- * @param param0 first param for the case
- * @param param1 second param for the case
- * @param filter_undefined should inputs that cause an undefined expectation be
- * filtered out, needed for const-eval
- */
-function makeCase(param0: number, param1: number, filter_undefined: boolean): Case | undefined {
- param0 = quantizeToF32(param0);
- param1 = quantizeToF32(param1);
-
- const results = pack2x16float(param0, param1);
- if (filter_undefined && results.some(r => r === undefined)) {
- return undefined;
- }
-
- return {
- input: [vec2(f32(param0), f32(param1))],
- expected: anyOf(
- ...results.map(r => (r === undefined ? skipUndefined(undefined) : skipUndefined(u32(r))))
- ),
- };
-}
-
-/**
- * @returns an array of Cases for `pack2x16float`
- * @param param0s array of inputs to try for the first param
- * @param param1s array of inputs to try for the second param
- * @param filter_undefined should inputs that cause an undefined expectation be
- * filtered out, needed for const-eval
- */
-function generateCases(param0s: number[], param1s: number[], filter_undefined: boolean): Case[] {
- return cartesianProduct(param0s, param1s)
- .map(e => makeCase(e[0], e[1], filter_undefined))
- .filter((c): c is Case => c !== undefined);
-}
-
-export const d = makeCaseCache('pack2x16float', {
- f32_const: () => {
- return generateCases(scalarF32Range(), scalarF32Range(), true);
- },
- f32_non_const: () => {
- return generateCases(scalarF32Range(), scalarF32Range(), false);
- },
-});
-
g.test('pack')
.specURL('https://www.w3.org/TR/WGSL/#pack-builtin-functions')
.desc(
diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack2x16snorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack2x16snorm.spec.ts
index 54bb21f6c645..6479fe7ce070 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/pack2x16snorm.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/pack2x16snorm.spec.ts
@@ -18,7 +18,8 @@ import {
vec2,
} from '../../../../../util/conversion.js';
import { quantizeToF32, vectorF32Range } from '../../../../../util/math.js';
-import { allInputSources, Case, run } from '../../expression.js';
+import { Case } from '../../case.js';
+import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack2x16unorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack2x16unorm.spec.ts
index a875a9c7e13a..303c555c1daf 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/pack2x16unorm.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/pack2x16unorm.spec.ts
@@ -18,7 +18,8 @@ import {
vec2,
} from '../../../../../util/conversion.js';
import { quantizeToF32, vectorF32Range } from '../../../../../util/math.js';
-import { allInputSources, Case, run } from '../../expression.js';
+import { Case } from '../../case.js';
+import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack4x8snorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack4x8snorm.spec.ts
index de0463e9fc4c..b1c2607c940f 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/pack4x8snorm.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/pack4x8snorm.spec.ts
@@ -19,7 +19,8 @@ import {
vec4,
} from '../../../../../util/conversion.js';
import { quantizeToF32, vectorF32Range } from '../../../../../util/math.js';
-import { allInputSources, Case, run } from '../../expression.js';
+import { Case } from '../../case.js';
+import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack4x8unorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack4x8unorm.spec.ts
index b670e92fbbbf..fa67e8f4ae3d 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/pack4x8unorm.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/pack4x8unorm.spec.ts
@@ -19,7 +19,8 @@ import {
vec4,
} from '../../../../../util/conversion.js';
import { quantizeToF32, vectorF32Range } from '../../../../../util/math.js';
-import { allInputSources, Case, run } from '../../expression.js';
+import { Case } from '../../case.js';
+import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
diff --git a/src/webgpu/shader/execution/expression/call/builtin/pow.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/pow.cache.ts
new file mode 100644
index 000000000000..ff2803747599
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/pow.cache.ts
@@ -0,0 +1,20 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarPairToIntervalCases(
+ FP[trait].scalarRange(),
+ FP[trait].scalarRange(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].powInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('pow', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/pow.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pow.spec.ts
index 6e682168de78..deea077e7a31 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/pow.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/pow.spec.ts
@@ -9,33 +9,14 @@ Returns e1 raised to the power e2. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './pow.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarPairToIntervalCases(
- FP[trait].scalarRange(),
- FP[trait].scalarRange(),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].powInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('pow', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.cache.ts
new file mode 100644
index 000000000000..91aa845d29f7
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.cache.ts
@@ -0,0 +1,41 @@
+import { kValue } from '../../../../../util/constants.js';
+import { FP } from '../../../../../util/floating_point.js';
+import { scalarF16Range, scalarF32Range } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+export const d = makeCaseCache('quantizeToF16', {
+ f32_const: () => {
+ return FP.f32.generateScalarToIntervalCases(
+ [
+ kValue.f16.negative.min,
+ kValue.f16.negative.max,
+ kValue.f16.negative.subnormal.min,
+ kValue.f16.negative.subnormal.max,
+ kValue.f16.positive.subnormal.min,
+ kValue.f16.positive.subnormal.max,
+ kValue.f16.positive.min,
+ kValue.f16.positive.max,
+ ...scalarF16Range(),
+ ],
+ 'finite',
+ FP.f32.quantizeToF16Interval
+ );
+ },
+ f32_non_const: () => {
+ return FP.f32.generateScalarToIntervalCases(
+ [
+ kValue.f16.negative.min,
+ kValue.f16.negative.max,
+ kValue.f16.negative.subnormal.min,
+ kValue.f16.negative.subnormal.max,
+ kValue.f16.positive.subnormal.min,
+ kValue.f16.positive.subnormal.max,
+ kValue.f16.positive.min,
+ kValue.f16.positive.max,
+ ...scalarF32Range(),
+ ],
+ 'unfiltered',
+ FP.f32.quantizeToF16Interval
+ );
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.spec.ts
index d48dfddb09c5..ee34ddd17479 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.spec.ts
@@ -10,54 +10,14 @@ Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { kValue } from '../../../../../util/constants.js';
import { TypeF32 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { scalarF16Range, scalarF32Range } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './quantizeToF16.cache.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('quantizeToF16', {
- f32_const: () => {
- return FP.f32.generateScalarToIntervalCases(
- [
- kValue.f16.negative.min,
- kValue.f16.negative.max,
- kValue.f16.negative.subnormal.min,
- kValue.f16.negative.subnormal.max,
- kValue.f16.positive.subnormal.min,
- kValue.f16.positive.subnormal.max,
- kValue.f16.positive.min,
- kValue.f16.positive.max,
- ...scalarF16Range(),
- ],
- 'finite',
- FP.f32.quantizeToF16Interval
- );
- },
- f32_non_const: () => {
- return FP.f32.generateScalarToIntervalCases(
- [
- kValue.f16.negative.min,
- kValue.f16.negative.max,
- kValue.f16.negative.subnormal.min,
- kValue.f16.negative.subnormal.max,
- kValue.f16.positive.subnormal.min,
- kValue.f16.positive.subnormal.max,
- kValue.f16.positive.min,
- kValue.f16.positive.max,
- ...scalarF32Range(),
- ],
- 'unfiltered',
- FP.f32.quantizeToF16Interval
- );
- },
-});
-
g.test('f32')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`f32 tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/radians.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/radians.cache.ts
new file mode 100644
index 000000000000..e92b4970c499
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/radians.cache.ts
@@ -0,0 +1,17 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ 'unfiltered',
+ FP[trait].radiansInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('radians', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/radians.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/radians.spec.ts
index 0404ff3d6df4..f83f89b9154e 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/radians.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/radians.spec.ts
@@ -11,29 +11,13 @@ Component-wise when T is a vector
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './radians.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16|abstract]
-const cases = (['f32', 'f16', 'abstract'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- 'unfiltered',
- FP[trait].radiansInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('radians', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/reflect.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/reflect.cache.ts
new file mode 100644
index 000000000000..5cfb33e55915
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/reflect.cache.ts
@@ -0,0 +1,22 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_vecN_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([2, 3, 4] as const).flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateVectorPairToVectorCases(
+ FP[trait].sparseVectorRange(dim),
+ FP[trait].sparseVectorRange(dim),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].reflectInterval
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('reflect', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/reflect.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/reflect.spec.ts
index 86e04271f665..0908bf04be5c 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/reflect.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/reflect.spec.ts
@@ -9,35 +9,14 @@ direction e1-2*dot(e2,e1)*e2.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './reflect.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_vecN_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([2, 3, 4] as const).flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateVectorPairToVectorCases(
- FP[trait].sparseVectorRange(dim),
- FP[trait].sparseVectorRange(dim),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].reflectInterval
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('reflect', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/refract.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/refract.cache.ts
new file mode 100644
index 000000000000..b426045e9b15
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/refract.cache.ts
@@ -0,0 +1,89 @@
+import { ROArrayArray } from '../../../../../../common/util/types.js';
+import { toVector } from '../../../../../util/conversion.js';
+import { FP, FPKind } from '../../../../../util/floating_point.js';
+import { Case } from '../../case.js';
+import { makeCaseCache } from '../../case_cache.js';
+import { IntervalFilter } from '../../interval_filter.js';
+
+// Using a bespoke implementation of make*Case and generate*Cases here
+// since refract is the only builtin with the API signature
+// (vec, vec, scalar) -> vec
+
+/**
+ * @returns a Case for `refract`
+ * @param kind what type of floating point numbers to operate on
+ * @param i the `i` param for the case
+ * @param s the `s` param for the case
+ * @param r the `r` param for the case
+ * @param check what interval checking to apply
+ * */
+function makeCase(
+ kind: FPKind,
+ i: readonly number[],
+ s: readonly number[],
+ r: number,
+ check: IntervalFilter
+): Case | undefined {
+ const fp = FP[kind];
+ i = i.map(fp.quantize);
+ s = s.map(fp.quantize);
+ r = fp.quantize(r);
+
+ const vectors = fp.refractInterval(i, s, r);
+ if (check === 'finite' && vectors.some(e => !e.isFinite())) {
+ return undefined;
+ }
+
+ return {
+ input: [toVector(i, fp.scalarBuilder), toVector(s, fp.scalarBuilder), fp.scalarBuilder(r)],
+ expected: fp.refractInterval(i, s, r),
+ };
+}
+
+/**
+ * @returns an array of Cases for `refract`
+ * @param kind what type of floating point numbers to operate on
+ * @param param_is array of inputs to try for the `i` param
+ * @param param_ss array of inputs to try for the `s` param
+ * @param param_rs array of inputs to try for the `r` param
+ * @param check what interval checking to apply
+ */
+function generateCases(
+ kind: FPKind,
+ param_is: ROArrayArray,
+ param_ss: ROArrayArray,
+ param_rs: readonly number[],
+ check: IntervalFilter
+): Case[] {
+ // Cannot use `cartesianProduct` here due to heterogeneous param types
+ return param_is
+ .flatMap(i => {
+ return param_ss.flatMap(s => {
+ return param_rs.map(r => {
+ return makeCase(kind, i, s, r, check);
+ });
+ });
+ })
+ .filter((c): c is Case => c !== undefined);
+}
+
+// Cases: [f32|f16]_vecN_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([2, 3, 4] as const).flatMap(dim =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return generateCases(
+ trait,
+ FP[trait].sparseVectorRange(dim),
+ FP[trait].sparseVectorRange(dim),
+ FP[trait].sparseScalarRange(),
+ nonConst ? 'unfiltered' : 'finite'
+ );
+ },
+ }))
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('refract', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/refract.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/refract.spec.ts
index 30253f9ce09c..67eb8ac94658 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/refract.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/refract.spec.ts
@@ -11,100 +11,15 @@ vector e3*e1- (e3* dot(e2,e1) + sqrt(k)) *e2.
`;
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
-import { ROArrayArray } from '../../../../../../common/util/types.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { toVector, TypeF32, TypeF16, TypeVec } from '../../../../../util/conversion.js';
-import { FP, FPKind } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
-import { allInputSources, Case, IntervalFilter, run } from '../../expression.js';
+import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js';
+import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './refract.cache.js';
export const g = makeTestGroup(GPUTest);
-// Using a bespoke implementation of make*Case and generate*Cases here
-// since refract is the only builtin with the API signature
-// (vec, vec, scalar) -> vec
-
-/**
- * @returns a Case for `refract`
- * @param kind what type of floating point numbers to operate on
- * @param i the `i` param for the case
- * @param s the `s` param for the case
- * @param r the `r` param for the case
- * @param check what interval checking to apply
- * */
-function makeCase(
- kind: FPKind,
- i: readonly number[],
- s: readonly number[],
- r: number,
- check: IntervalFilter
-): Case | undefined {
- const fp = FP[kind];
- i = i.map(fp.quantize);
- s = s.map(fp.quantize);
- r = fp.quantize(r);
-
- const vectors = fp.refractInterval(i, s, r);
- if (check === 'finite' && vectors.some(e => !e.isFinite())) {
- return undefined;
- }
-
- return {
- input: [toVector(i, fp.scalarBuilder), toVector(s, fp.scalarBuilder), fp.scalarBuilder(r)],
- expected: fp.refractInterval(i, s, r),
- };
-}
-
-/**
- * @returns an array of Cases for `refract`
- * @param kind what type of floating point numbers to operate on
- * @param param_is array of inputs to try for the `i` param
- * @param param_ss array of inputs to try for the `s` param
- * @param param_rs array of inputs to try for the `r` param
- * @param check what interval checking to apply
- */
-function generateCases(
- kind: FPKind,
- param_is: ROArrayArray,
- param_ss: ROArrayArray,
- param_rs: readonly number[],
- check: IntervalFilter
-): Case[] {
- // Cannot use `cartesianProduct` here due to heterogeneous param types
- return param_is
- .flatMap(i => {
- return param_ss.flatMap(s => {
- return param_rs.map(r => {
- return makeCase(kind, i, s, r, check);
- });
- });
- })
- .filter((c): c is Case => c !== undefined);
-}
-
-// Cases: [f32|f16]_vecN_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([2, 3, 4] as const).flatMap(dim =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_vec${dim}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return generateCases(
- trait,
- FP[trait].sparseVectorRange(dim),
- FP[trait].sparseVectorRange(dim),
- FP[trait].sparseScalarRange(),
- nonConst ? 'unfiltered' : 'finite'
- );
- },
- }))
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('refract', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/round.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/round.cache.ts
new file mode 100644
index 000000000000..e5383b2075ed
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/round.cache.ts
@@ -0,0 +1,24 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// See https://github.com/gpuweb/cts/issues/2766 for details
+const kIssue2766Value = {
+ abstract: 0x8000_0000_0000_0000,
+ f32: 0x8000_0000,
+ f16: 0x8000,
+};
+
+// Cases: [f32|f16|abstract]
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [kIssue2766Value[trait], ...FP[trait].scalarRange()],
+ 'unfiltered',
+ FP[trait].roundInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('round', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/round.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/round.spec.ts
index 307490b835df..de2d6acfd0e1 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/round.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/round.spec.ts
@@ -12,37 +12,14 @@ Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16, TypeAbstractFloat } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './round.cache.js';
export const g = makeTestGroup(GPUTest);
-// See https://github.com/gpuweb/cts/issues/2766 for details
-const kIssue2766Value = {
- abstract: 0x8000_0000_0000_0000,
- f32: 0x8000_0000,
- f16: 0x8000,
-};
-
-// Cases: [f32|f16|abstract]
-const cases = (['f32', 'f16', 'abstract'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [kIssue2766Value[trait], ...FP[trait].scalarRange()],
- 'unfiltered',
- FP[trait].roundInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('round', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/saturate.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/saturate.cache.ts
new file mode 100644
index 000000000000..4a4ffeee30f7
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/saturate.cache.ts
@@ -0,0 +1,18 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [...linearRange(0.0, 1.0, 20), ...FP[trait].scalarRange()],
+ 'unfiltered',
+ FP[trait].saturateInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('saturate', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/saturate.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/saturate.spec.ts
index 429d5a322dae..bf19a3c6cb23 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/saturate.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/saturate.spec.ts
@@ -10,30 +10,13 @@ Returns clamp(e, 0.0, 1.0). Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './saturate.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16|abstract]
-const cases = (['f32', 'f16', 'abstract'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [...linearRange(0.0, 1.0, 20), ...FP[trait].scalarRange()],
- 'unfiltered',
- FP[trait].saturateInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('saturate', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/select.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/select.spec.ts
index c64f989f4218..e69ab1886e03 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/select.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/select.spec.ts
@@ -33,7 +33,8 @@ import {
abstractFloat,
TypeAbstractFloat,
} from '../../../../../util/conversion.js';
-import { run, CaseList, allInputSources } from '../../expression.js';
+import { CaseList } from '../../case.js';
+import { run, allInputSources } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
diff --git a/src/webgpu/shader/execution/expression/call/builtin/sign.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/sign.cache.ts
new file mode 100644
index 000000000000..8bac506ddc3a
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/sign.cache.ts
@@ -0,0 +1,26 @@
+import { i32 } from '../../../../../util/conversion.js';
+import { FP } from '../../../../../util/floating_point.js';
+import { fullI32Range } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]
+const fp_cases = (['f32', 'f16', 'abstract'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ 'unfiltered',
+ FP[trait].signInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('sign', {
+ ...fp_cases,
+ i32: () =>
+ fullI32Range().map(i => {
+ const signFunc = (i: number): number => (i < 0 ? -1 : i > 0 ? 1 : 0);
+ return { input: [i32(i)], expected: i32(signFunc(i)) };
+ }),
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/sign.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/sign.spec.ts
index 91d62148bf49..a17bb7b205ac 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/sign.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/sign.spec.ts
@@ -9,44 +9,14 @@ Returns the sign of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import {
- i32,
- TypeF32,
- TypeF16,
- TypeI32,
- TypeAbstractFloat,
-} from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { fullI32Range } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeAbstractFloat, TypeF16, TypeF32, TypeI32 } from '../../../../../util/conversion.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './sign.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16|abstract]
-const fp_cases = (['f32', 'f16', 'abstract'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- 'unfiltered',
- FP[trait].signInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('sign', {
- ...fp_cases,
- i32: () =>
- fullI32Range().map(i => {
- const signFunc = (i: number): number => (i < 0 ? -1 : i > 0 ? 1 : 0);
- return { input: [i32(i)], expected: i32(signFunc(i)) };
- }),
-});
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#sign-builtin')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/sin.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/sin.cache.ts
new file mode 100644
index 000000000000..6c107d62dd11
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/sin.cache.ts
@@ -0,0 +1,22 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]
+const cases = (['f32', 'f16'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [
+ // Well-defined accuracy range
+ ...linearRange(-Math.PI, Math.PI, 100),
+ ...FP[trait].scalarRange(),
+ ],
+ 'unfiltered',
+ FP[trait].sinInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('sin', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/sin.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/sin.spec.ts
index 6507d3aeddc1..e9420fc0880d 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/sin.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/sin.spec.ts
@@ -9,35 +9,14 @@ Returns the sine of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './sin.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]
-const cases = (['f32', 'f16'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [
- // Well-defined accuracy range
- ...linearRange(-Math.PI, Math.PI, 100),
- ...FP[trait].scalarRange(),
- ],
- 'unfiltered',
- FP[trait].sinInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('sin', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/sinh.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/sinh.cache.ts
new file mode 100644
index 000000000000..4a4d776292f3
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/sinh.cache.ts
@@ -0,0 +1,19 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].sinhInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('sinh', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/sinh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/sinh.spec.ts
index 18268211d366..0070befa47fc 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/sinh.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/sinh.spec.ts
@@ -9,32 +9,14 @@ Returns the hyperbolic sine of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './sinh.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].sinhInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('sinh', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/smoothstep.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/smoothstep.cache.ts
new file mode 100644
index 000000000000..1c918aacc056
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/smoothstep.cache.ts
@@ -0,0 +1,21 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarTripleToIntervalCases(
+ FP[trait].sparseScalarRange(),
+ FP[trait].sparseScalarRange(),
+ FP[trait].sparseScalarRange(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].smoothStepInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('smoothstep', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/smoothstep.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/smoothstep.spec.ts
index fb6e166dacc4..a32c112b8a94 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/smoothstep.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/smoothstep.spec.ts
@@ -11,34 +11,14 @@ For scalar T, the result is t * t * (3.0 - 2.0 * t), where t = clamp((x - low) /
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './smoothstep.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarTripleToIntervalCases(
- FP[trait].sparseScalarRange(),
- FP[trait].sparseScalarRange(),
- FP[trait].sparseScalarRange(),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].smoothStepInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('smoothstep', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/sqrt.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/sqrt.cache.ts
new file mode 100644
index 000000000000..f350eaff3576
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/sqrt.cache.ts
@@ -0,0 +1,19 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]_[non_]const
+const cases = (['f32', 'f16'] as const)
+ .flatMap(trait =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].sqrtInterval
+ );
+ },
+ }))
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('sqrt', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/sqrt.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/sqrt.spec.ts
index 4954ddf9ab51..cfd379fea660 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/sqrt.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/sqrt.spec.ts
@@ -9,32 +9,14 @@ Returns the square root of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './sqrt.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]_[non_]const
-const cases = (['f32', 'f16'] as const)
- .flatMap(trait =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].sqrtInterval
- );
- },
- }))
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('sqrt', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/step.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/step.cache.ts
new file mode 100644
index 000000000000..c741f8fd2603
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/step.cache.ts
@@ -0,0 +1,41 @@
+import { anyOf } from '../../../../../util/compare.js';
+import { FP } from '../../../../../util/floating_point.js';
+import { Case } from '../../case.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// stepInterval's return value can't always be interpreted as a single acceptance
+// interval, valid result may be 0.0 or 1.0 or both of them, but will never be a
+// value in interval (0.0, 1.0).
+// See the comment block on stepInterval for more details
+const makeCase = (trait: 'f32' | 'f16', edge: number, x: number): Case => {
+ const FPTrait = FP[trait];
+ edge = FPTrait.quantize(edge);
+ x = FPTrait.quantize(x);
+ const expected = FPTrait.stepInterval(edge, x);
+
+ // [0, 0], [1, 1], or [-∞, +∞] cases
+ if (expected.isPoint() || !expected.isFinite()) {
+ return { input: [FPTrait.scalarBuilder(edge), FPTrait.scalarBuilder(x)], expected };
+ }
+
+ // [0, 1] case, valid result is either 0.0 or 1.0.
+ const zeroInterval = FPTrait.toInterval(0);
+ const oneInterval = FPTrait.toInterval(1);
+ return {
+ input: [FPTrait.scalarBuilder(edge), FPTrait.scalarBuilder(x)],
+ expected: anyOf(zeroInterval, oneInterval),
+ };
+};
+
+// Cases: [f32|f16]
+const cases = (['f32', 'f16'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait]
+ .scalarRange()
+ .flatMap(edge => FP[trait].scalarRange().map(x => makeCase(trait, edge, x)));
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('step', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/step.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/step.spec.ts
index 2e8f7ce8a070..c55a48812e9c 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/step.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/step.spec.ts
@@ -9,53 +9,14 @@ Returns 1.0 if edge ≤ x, and 0.0 otherwise. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { anyOf } from '../../../../../util/compare.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
-import { allInputSources, Case, run } from '../../expression.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
+import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './step.cache.js';
export const g = makeTestGroup(GPUTest);
-// stepInterval's return value can't always be interpreted as a single acceptance
-// interval, valid result may be 0.0 or 1.0 or both of them, but will never be a
-// value in interval (0.0, 1.0).
-// See the comment block on stepInterval for more details
-const makeCase = (trait: 'f32' | 'f16', edge: number, x: number): Case => {
- const FPTrait = FP[trait];
- edge = FPTrait.quantize(edge);
- x = FPTrait.quantize(x);
- const expected = FPTrait.stepInterval(edge, x);
-
- // [0, 0], [1, 1], or [-∞, +∞] cases
- if (expected.isPoint() || !expected.isFinite()) {
- return { input: [FPTrait.scalarBuilder(edge), FPTrait.scalarBuilder(x)], expected };
- }
-
- // [0, 1] case, valid result is either 0.0 or 1.0.
- const zeroInterval = FPTrait.toInterval(0);
- const oneInterval = FPTrait.toInterval(1);
- return {
- input: [FPTrait.scalarBuilder(edge), FPTrait.scalarBuilder(x)],
- expected: anyOf(zeroInterval, oneInterval),
- };
-};
-
-// Cases: [f32|f16]
-const cases = (['f32', 'f16'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait]
- .scalarRange()
- .flatMap(edge => FP[trait].scalarRange().map(x => makeCase(trait, edge, x)));
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('step', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/tan.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/tan.cache.ts
new file mode 100644
index 000000000000..cf850a5d78f0
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/tan.cache.ts
@@ -0,0 +1,22 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { linearRange } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]
+const cases = (['f32', 'f16'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ [
+ // Well-defined accuracy range
+ ...linearRange(-Math.PI, Math.PI, 100),
+ ...FP[trait].scalarRange(),
+ ],
+ 'unfiltered',
+ FP[trait].tanInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('tan', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/tan.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/tan.spec.ts
index b54f0b11052b..f86b3c959a16 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/tan.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/tan.spec.ts
@@ -9,35 +9,14 @@ Returns the tangent of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { linearRange } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './tan.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]
-const cases = (['f32', 'f16'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- [
- // Well-defined accuracy range
- ...linearRange(-Math.PI, Math.PI, 100),
- ...FP[trait].scalarRange(),
- ],
- 'unfiltered',
- FP[trait].tanInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('tan', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/tanh.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/tanh.cache.ts
new file mode 100644
index 000000000000..46724e6b7033
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/tanh.cache.ts
@@ -0,0 +1,17 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16]
+const cases = (['f32', 'f16'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ 'unfiltered',
+ FP[trait].tanhInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('tanh', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/tanh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/tanh.spec.ts
index 426181e79b05..496c7bcf1b11 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/tanh.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/tanh.spec.ts
@@ -9,30 +9,14 @@ Returns the hyperbolic tangent of e. Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
-import { TypeF32, TypeF16 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
+import { TypeF16, TypeF32 } from '../../../../../util/conversion.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './tanh.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16]
-const cases = (['f32', 'f16'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- 'unfiltered',
- FP[trait].tanhInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('tanh', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/transpose.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/transpose.cache.ts
new file mode 100644
index 000000000000..cb89e2d1944d
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/transpose.cache.ts
@@ -0,0 +1,27 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]_matCxR_[non_]const
+// abstract_matCxR_non_const is empty and not used
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .flatMap(trait =>
+ ([2, 3, 4] as const).flatMap(cols =>
+ ([2, 3, 4] as const).flatMap(rows =>
+ ([true, false] as const).map(nonConst => ({
+ [`${trait}_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
+ if (trait === 'abstract' && nonConst) {
+ return [];
+ }
+ return FP[trait].generateMatrixToMatrixCases(
+ FP[trait].sparseMatrixRange(cols, rows),
+ nonConst ? 'unfiltered' : 'finite',
+ FP[trait].transposeInterval
+ );
+ },
+ }))
+ )
+ )
+ )
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('transpose', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/transpose.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/transpose.spec.ts
index 502983517a76..82250cb985cf 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/transpose.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/transpose.spec.ts
@@ -9,39 +9,13 @@ Returns the transpose of e.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeAbstractFloat, TypeF16, TypeF32, TypeMat } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './transpose.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16|abstract]_matCxR_[non_]const
-// abstract_matCxR_non_const is empty and not used
-const cases = (['f32', 'f16', 'abstract'] as const)
- .flatMap(trait =>
- ([2, 3, 4] as const).flatMap(cols =>
- ([2, 3, 4] as const).flatMap(rows =>
- ([true, false] as const).map(nonConst => ({
- [`${trait}_mat${cols}x${rows}_${nonConst ? 'non_const' : 'const'}`]: () => {
- if (trait === 'abstract' && nonConst) {
- return [];
- }
- return FP[trait].generateMatrixToMatrixCases(
- FP[trait].sparseMatrixRange(cols, rows),
- nonConst ? 'unfiltered' : 'finite',
- FP[trait].transposeInterval
- );
- },
- }))
- )
- )
- )
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('transpose', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#matrix-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/trunc.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/trunc.cache.ts
new file mode 100644
index 000000000000..061c95b07fed
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/trunc.cache.ts
@@ -0,0 +1,17 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+// Cases: [f32|f16|abstract]
+const cases = (['f32', 'f16', 'abstract'] as const)
+ .map(trait => ({
+ [`${trait}`]: () => {
+ return FP[trait].generateScalarToIntervalCases(
+ FP[trait].scalarRange(),
+ 'unfiltered',
+ FP[trait].truncInterval
+ );
+ },
+ }))
+ .reduce((a, b) => ({ ...a, ...b }), {});
+
+export const d = makeCaseCache('trunc', cases);
diff --git a/src/webgpu/shader/execution/expression/call/builtin/trunc.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/trunc.spec.ts
index ce885450b85f..7dcc9395c3e3 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/trunc.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/trunc.spec.ts
@@ -11,29 +11,13 @@ Component-wise when T is a vector.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, onlyConstInputSource, run } from '../../expression.js';
import { abstractBuiltin, builtin } from './builtin.js';
+import { d } from './trunc.cache.js';
export const g = makeTestGroup(GPUTest);
-// Cases: [f32|f16|abstract]
-const cases = (['f32', 'f16', 'abstract'] as const)
- .map(trait => ({
- [`${trait}`]: () => {
- return FP[trait].generateScalarToIntervalCases(
- FP[trait].scalarRange(),
- 'unfiltered',
- FP[trait].truncInterval
- );
- },
- }))
- .reduce((a, b) => ({ ...a, ...b }), {});
-
-export const d = makeCaseCache('trunc', cases);
-
g.test('abstract_float')
.specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions')
.desc(`abstract float tests`)
diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.cache.ts
new file mode 100644
index 000000000000..79a7a568d22f
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.cache.ts
@@ -0,0 +1,20 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { fullU32Range } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+export const d = makeCaseCache('unpack2x16float', {
+ u32_const: () => {
+ return FP.f32.generateU32ToIntervalCases(
+ fullU32Range(),
+ 'finite',
+ FP.f32.unpack2x16floatInterval
+ );
+ },
+ u32_non_const: () => {
+ return FP.f32.generateU32ToIntervalCases(
+ fullU32Range(),
+ 'unfiltered',
+ FP.f32.unpack2x16floatInterval
+ );
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.spec.ts
index 4a0bf075e91f..da1819f8ef6e 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.spec.ts
@@ -8,32 +8,13 @@ interpretation of bits 16×i through 16×i+15 of e as an IEEE-754 binary16 value
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { fullU32Range } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './unpack2x16float.cache.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unpack2x16float', {
- u32_const: () => {
- return FP.f32.generateU32ToIntervalCases(
- fullU32Range(),
- 'finite',
- FP.f32.unpack2x16floatInterval
- );
- },
- u32_non_const: () => {
- return FP.f32.generateU32ToIntervalCases(
- fullU32Range(),
- 'unfiltered',
- FP.f32.unpack2x16floatInterval
- );
- },
-});
-
g.test('unpack')
.specURL('https://www.w3.org/TR/WGSL/#unpack-builtin-functions')
.desc(
diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.cache.ts
new file mode 100644
index 000000000000..89dfb475d390
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.cache.ts
@@ -0,0 +1,20 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { fullU32Range } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+export const d = makeCaseCache('unpack2x16snorm', {
+ u32_const: () => {
+ return FP.f32.generateU32ToIntervalCases(
+ fullU32Range(),
+ 'finite',
+ FP.f32.unpack2x16snormInterval
+ );
+ },
+ u32_non_const: () => {
+ return FP.f32.generateU32ToIntervalCases(
+ fullU32Range(),
+ 'unfiltered',
+ FP.f32.unpack2x16snormInterval
+ );
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.spec.ts
index 195cfd9a0111..a88702bcce70 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.spec.ts
@@ -8,32 +8,13 @@ of bits 16×i through 16×i+15 of e as a twos-complement signed integer.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { fullU32Range } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './unpack2x16snorm.cache.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unpack2x16snorm', {
- u32_const: () => {
- return FP.f32.generateU32ToIntervalCases(
- fullU32Range(),
- 'finite',
- FP.f32.unpack2x16snormInterval
- );
- },
- u32_non_const: () => {
- return FP.f32.generateU32ToIntervalCases(
- fullU32Range(),
- 'unfiltered',
- FP.f32.unpack2x16snormInterval
- );
- },
-});
-
g.test('unpack')
.specURL('https://www.w3.org/TR/WGSL/#unpack-builtin-functions')
.desc(
diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.cache.ts
new file mode 100644
index 000000000000..7f0fe84af600
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.cache.ts
@@ -0,0 +1,20 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { fullU32Range } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+export const d = makeCaseCache('unpack2x16unorm', {
+ u32_const: () => {
+ return FP.f32.generateU32ToIntervalCases(
+ fullU32Range(),
+ 'finite',
+ FP.f32.unpack2x16unormInterval
+ );
+ },
+ u32_non_const: () => {
+ return FP.f32.generateU32ToIntervalCases(
+ fullU32Range(),
+ 'unfiltered',
+ FP.f32.unpack2x16unormInterval
+ );
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.spec.ts
index 16b4e6397c6d..325e0a9735b5 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.spec.ts
@@ -8,32 +8,13 @@ Component i of the result is v ÷ 65535, where v is the interpretation of bits
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { fullU32Range } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './unpack2x16unorm.cache.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unpack2x16unorm', {
- u32_const: () => {
- return FP.f32.generateU32ToIntervalCases(
- fullU32Range(),
- 'finite',
- FP.f32.unpack2x16unormInterval
- );
- },
- u32_non_const: () => {
- return FP.f32.generateU32ToIntervalCases(
- fullU32Range(),
- 'unfiltered',
- FP.f32.unpack2x16unormInterval
- );
- },
-});
-
g.test('unpack')
.specURL('https://www.w3.org/TR/WGSL/#unpack-builtin-functions')
.desc(
diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.cache.ts
new file mode 100644
index 000000000000..3a4790f1882c
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.cache.ts
@@ -0,0 +1,20 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { fullU32Range } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+export const d = makeCaseCache('unpack4x8snorm', {
+ u32_const: () => {
+ return FP.f32.generateU32ToIntervalCases(
+ fullU32Range(),
+ 'finite',
+ FP.f32.unpack4x8snormInterval
+ );
+ },
+ u32_non_const: () => {
+ return FP.f32.generateU32ToIntervalCases(
+ fullU32Range(),
+ 'unfiltered',
+ FP.f32.unpack4x8snormInterval
+ );
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.spec.ts
index 7ea8d5191895..3b48cca4539f 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.spec.ts
@@ -8,32 +8,13 @@ bits 8×i through 8×i+7 of e as a twos-complement signed integer.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { fullU32Range } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './unpack4x8snorm.cache.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unpack4x8snorm', {
- u32_const: () => {
- return FP.f32.generateU32ToIntervalCases(
- fullU32Range(),
- 'finite',
- FP.f32.unpack4x8snormInterval
- );
- },
- u32_non_const: () => {
- return FP.f32.generateU32ToIntervalCases(
- fullU32Range(),
- 'unfiltered',
- FP.f32.unpack4x8snormInterval
- );
- },
-});
-
g.test('unpack')
.specURL('https://www.w3.org/TR/WGSL/#unpack-builtin-functions')
.desc(
diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.cache.ts
new file mode 100644
index 000000000000..21390f74b19f
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.cache.ts
@@ -0,0 +1,20 @@
+import { FP } from '../../../../../util/floating_point.js';
+import { fullU32Range } from '../../../../../util/math.js';
+import { makeCaseCache } from '../../case_cache.js';
+
+export const d = makeCaseCache('unpack4x8unorm', {
+ u32_const: () => {
+ return FP.f32.generateU32ToIntervalCases(
+ fullU32Range(),
+ 'finite',
+ FP.f32.unpack4x8unormInterval
+ );
+ },
+ u32_non_const: () => {
+ return FP.f32.generateU32ToIntervalCases(
+ fullU32Range(),
+ 'unfiltered',
+ FP.f32.unpack4x8unormInterval
+ );
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.spec.ts
index bf54d23c12e1..3e57f2592ee5 100644
--- a/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.spec.ts
+++ b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.spec.ts
@@ -8,32 +8,13 @@ through 8×i+7 of e as an unsigned integer.
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { GPUTest } from '../../../../../gpu_test.js';
import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js';
-import { FP } from '../../../../../util/floating_point.js';
-import { fullU32Range } from '../../../../../util/math.js';
-import { makeCaseCache } from '../../case_cache.js';
import { allInputSources, run } from '../../expression.js';
import { builtin } from './builtin.js';
+import { d } from './unpack4x8unorm.cache.js';
export const g = makeTestGroup(GPUTest);
-export const d = makeCaseCache('unpack4x8unorm', {
- u32_const: () => {
- return FP.f32.generateU32ToIntervalCases(
- fullU32Range(),
- 'finite',
- FP.f32.unpack4x8unormInterval
- );
- },
- u32_non_const: () => {
- return FP.f32.generateU32ToIntervalCases(
- fullU32Range(),
- 'unfiltered',
- FP.f32.unpack4x8unormInterval
- );
- },
-});
-
g.test('unpack')
.specURL('https://www.w3.org/TR/WGSL/#unpack-builtin-functions')
.desc(
diff --git a/src/webgpu/shader/execution/expression/case.ts b/src/webgpu/shader/execution/expression/case.ts
new file mode 100644
index 000000000000..65fd85d77bbc
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/case.ts
@@ -0,0 +1,247 @@
+import { ROArrayArray } from '../../../../common/util/types.js';
+import { ScalarBuilder, Value, Vector, i32, u32 } from '../../../util/conversion.js';
+import {
+ QuantizeFunc,
+ cartesianProduct,
+ quantizeToI32,
+ quantizeToU32,
+} from '../../../util/math.js';
+
+import { Expectation } from './expectation.js';
+
+/** Case is a single expression test case. */
+export type Case = {
+ // The input value(s)
+ input: Value | ReadonlyArray;
+ // The expected result, or function to check the result
+ expected: Expectation;
+};
+
+/** CaseList is a list of Cases */
+export type CaseList = Array;
+
+/**
+ * A function that performs a binary operation on x and y, and returns the expected
+ * result.
+ */
+export interface BinaryOp {
+ (x: number, y: number): number | undefined;
+}
+
+/**
+ * @returns a Case for the input params with op applied
+ * @param scalar scalar param
+ * @param vector vector param (2, 3, or 4 elements)
+ * @param op the op to apply to scalar and vector
+ * @param quantize function to quantize all values in vectors and scalars
+ * @param scalarize function to convert numbers to Scalars
+ */
+function makeScalarVectorBinaryToVectorCase(
+ scalar: number,
+ vector: readonly number[],
+ op: BinaryOp,
+ quantize: QuantizeFunc,
+ scalarize: ScalarBuilder
+): Case | undefined {
+ scalar = quantize(scalar);
+ vector = vector.map(quantize);
+ const result = vector.map(v => op(scalar, v));
+ if (result.includes(undefined)) {
+ return undefined;
+ }
+ return {
+ input: [scalarize(scalar), new Vector(vector.map(scalarize))],
+ expected: new Vector((result as readonly number[]).map(scalarize)),
+ };
+}
+
+/**
+ * @returns array of Case for the input params with op applied
+ * @param scalars array of scalar params
+ * @param vectors array of vector params (2, 3, or 4 elements)
+ * @param op the op to apply to each pair of scalar and vector
+ * @param quantize function to quantize all values in vectors and scalars
+ * @param scalarize function to convert numbers to Scalars
+ */
+function generateScalarVectorBinaryToVectorCases(
+ scalars: readonly number[],
+ vectors: ROArrayArray,
+ op: BinaryOp,
+ quantize: QuantizeFunc,
+ scalarize: ScalarBuilder
+): Case[] {
+ const cases = new Array();
+ scalars.forEach(s => {
+ vectors.forEach(v => {
+ const c = makeScalarVectorBinaryToVectorCase(s, v, op, quantize, scalarize);
+ if (c !== undefined) {
+ cases.push(c);
+ }
+ });
+ });
+ return cases;
+}
+
+/**
+ * @returns a Case for the input params with op applied
+ * @param vector vector param (2, 3, or 4 elements)
+ * @param scalar scalar param
+ * @param op the op to apply to vector and scalar
+ * @param quantize function to quantize all values in vectors and scalars
+ * @param scalarize function to convert numbers to Scalars
+ */
+function makeVectorScalarBinaryToVectorCase(
+ vector: readonly number[],
+ scalar: number,
+ op: BinaryOp,
+ quantize: QuantizeFunc,
+ scalarize: ScalarBuilder
+): Case | undefined {
+ vector = vector.map(quantize);
+ scalar = quantize(scalar);
+ const result = vector.map(v => op(v, scalar));
+ if (result.includes(undefined)) {
+ return undefined;
+ }
+ return {
+ input: [new Vector(vector.map(scalarize)), scalarize(scalar)],
+ expected: new Vector((result as readonly number[]).map(scalarize)),
+ };
+}
+
+/**
+ * @returns array of Case for the input params with op applied
+ * @param vectors array of vector params (2, 3, or 4 elements)
+ * @param scalars array of scalar params
+ * @param op the op to apply to each pair of vector and scalar
+ * @param quantize function to quantize all values in vectors and scalars
+ * @param scalarize function to convert numbers to Scalars
+ */
+function generateVectorScalarBinaryToVectorCases(
+ vectors: ROArrayArray,
+ scalars: readonly number[],
+ op: BinaryOp,
+ quantize: QuantizeFunc,
+ scalarize: ScalarBuilder
+): Case[] {
+ const cases = new Array();
+ scalars.forEach(s => {
+ vectors.forEach(v => {
+ const c = makeVectorScalarBinaryToVectorCase(v, s, op, quantize, scalarize);
+ if (c !== undefined) {
+ cases.push(c);
+ }
+ });
+ });
+ return cases;
+}
+
+/**
+ * @returns array of Case for the input params with op applied
+ * @param scalars array of scalar params
+ * @param vectors array of vector params (2, 3, or 4 elements)
+ * @param op he op to apply to each pair of scalar and vector
+ */
+export function generateU32VectorBinaryToVectorCases(
+ scalars: readonly number[],
+ vectors: ROArrayArray,
+ op: BinaryOp
+): Case[] {
+ return generateScalarVectorBinaryToVectorCases(scalars, vectors, op, quantizeToU32, u32);
+}
+
+/**
+ * @returns array of Case for the input params with op applied
+ * @param vectors array of vector params (2, 3, or 4 elements)
+ * @param scalars array of scalar params
+ * @param op he op to apply to each pair of vector and scalar
+ */
+export function generateVectorU32BinaryToVectorCases(
+ vectors: ROArrayArray,
+ scalars: readonly number[],
+ op: BinaryOp
+): Case[] {
+ return generateVectorScalarBinaryToVectorCases(vectors, scalars, op, quantizeToU32, u32);
+}
+
+/**
+ * @returns array of Case for the input params with op applied
+ * @param scalars array of scalar params
+ * @param vectors array of vector params (2, 3, or 4 elements)
+ * @param op he op to apply to each pair of scalar and vector
+ */
+export function generateI32VectorBinaryToVectorCases(
+ scalars: readonly number[],
+ vectors: ROArrayArray,
+ op: BinaryOp
+): Case[] {
+ return generateScalarVectorBinaryToVectorCases(scalars, vectors, op, quantizeToI32, i32);
+}
+
+/**
+ * @returns array of Case for the input params with op applied
+ * @param vectors array of vector params (2, 3, or 4 elements)
+ * @param scalars array of scalar params
+ * @param op he op to apply to each pair of vector and scalar
+ */
+export function generateVectorI32BinaryToVectorCases(
+ vectors: ROArrayArray,
+ scalars: readonly number[],
+ op: BinaryOp
+): Case[] {
+ return generateVectorScalarBinaryToVectorCases(vectors, scalars, op, quantizeToI32, i32);
+}
+
+/**
+ * @returns array of Case for the input params with op applied
+ * @param param0s array of inputs to try for the first param
+ * @param param1s array of inputs to try for the second param
+ * @param op callback called on each pair of inputs to produce each case
+ * @param quantize function to quantize all values
+ * @param scalarize function to convert numbers to Scalars
+ */
+function generateScalarBinaryToScalarCases(
+ param0s: readonly number[],
+ param1s: readonly number[],
+ op: BinaryOp,
+ quantize: QuantizeFunc,
+ scalarize: ScalarBuilder
+): Case[] {
+ param0s = param0s.map(quantize);
+ param1s = param1s.map(quantize);
+ return cartesianProduct(param0s, param1s).reduce((cases, e) => {
+ const expected = op(e[0], e[1]);
+ if (expected !== undefined) {
+ cases.push({ input: [scalarize(e[0]), scalarize(e[1])], expected: scalarize(expected) });
+ }
+ return cases;
+ }, new Array());
+}
+
+/**
+ * @returns an array of Cases for operations over a range of inputs
+ * @param param0s array of inputs to try for the first param
+ * @param param1s array of inputs to try for the second param
+ * @param op callback called on each pair of inputs to produce each case
+ */
+export function generateBinaryToI32Cases(
+ param0s: readonly number[],
+ param1s: readonly number[],
+ op: BinaryOp
+) {
+ return generateScalarBinaryToScalarCases(param0s, param1s, op, quantizeToI32, i32);
+}
+
+/**
+ * @returns an array of Cases for operations over a range of inputs
+ * @param param0s array of inputs to try for the first param
+ * @param param1s array of inputs to try for the second param
+ * @param op callback called on each pair of inputs to produce each case
+ */
+export function generateBinaryToU32Cases(
+ param0s: readonly number[],
+ param1s: readonly number[],
+ op: BinaryOp
+) {
+ return generateScalarBinaryToScalarCases(param0s, param1s, op, quantizeToU32, u32);
+}
diff --git a/src/webgpu/shader/execution/expression/case_cache.ts b/src/webgpu/shader/execution/expression/case_cache.ts
index f9bfd3c00b21..1580cf3298ca 100644
--- a/src/webgpu/shader/execution/expression/case_cache.ts
+++ b/src/webgpu/shader/execution/expression/case_cache.ts
@@ -3,21 +3,22 @@ import { unreachable } from '../../../../common/util/util.js';
import BinaryStream from '../../../util/binary_stream.js';
import { deserializeComparator, serializeComparator } from '../../../util/compare.js';
import {
+ Matrix,
Scalar,
+ Value,
Vector,
- serializeValue,
deserializeValue,
- Matrix,
- Value,
+ serializeValue,
} from '../../../util/conversion.js';
import {
- deserializeFPInterval,
FPInterval,
+ deserializeFPInterval,
serializeFPInterval,
} from '../../../util/floating_point.js';
import { flatten2DArray, unflatten2DArray } from '../../../util/math.js';
-import { Case, CaseList, Expectation, isComparator } from './expression.js';
+import { Case, CaseList } from './case.js';
+import { Expectation, isComparator } from './expectation.js';
enum SerializedExpectationKind {
Value,
@@ -164,7 +165,7 @@ export class CaseCache implements Cacheable> {
* serialize() implements the Cacheable.serialize interface.
* @returns the serialized data.
*/
- async serialize(data: Record): Promise {
+ serialize(data: Record): Uint8Array {
const maxSize = 32 << 20; // 32MB - max size for a file
const stream = new BinaryStream(new ArrayBuffer(maxSize));
stream.writeU32(Object.keys(data).length);
@@ -172,17 +173,15 @@ export class CaseCache implements Cacheable> {
stream.writeString(name);
stream.writeArray(data[name], serializeCase);
}
- const compressed = this.compress('gzip', stream.buffer());
- return compressed;
+ return stream.buffer();
}
/**
* deserialize() implements the Cacheable.deserialize interface.
* @returns the deserialize data.
*/
- async deserialize(array: Uint8Array): Promise> {
- const decompressed = await this.decompress('gzip', array);
- const s = new BinaryStream(decompressed);
+ deserialize(array: Uint8Array): Record {
+ const s = new BinaryStream(array.buffer);
const casesByName: Record = {};
const numRecords = s.readU32();
for (let i = 0; i < numRecords; i++) {
@@ -193,26 +192,6 @@ export class CaseCache implements Cacheable> {
return casesByName;
}
- /**
- * Compresses a Uint8Array using using the given CompressionFormat
- */
- private async compress(format: CompressionFormat, data: Uint8Array): Promise {
- const stream = new Blob([data]).stream();
- const compressedStream = stream.pipeThrough(new CompressionStream(format));
- const blob = await new Response(compressedStream).blob();
- return new Uint8Array(await blob.arrayBuffer());
- }
-
- /**
- * Decompresses a Uint8Array using using gzip
- */
- private async decompress(format: CompressionFormat, data: Uint8Array): Promise {
- const stream = new Blob([data]).stream();
- const decompressedStream = stream.pipeThrough(new DecompressionStream(format));
- const blob = await new Response(decompressedStream).blob();
- return await blob.arrayBuffer();
- }
-
public readonly path: string;
private readonly builders: Record;
}
diff --git a/src/webgpu/shader/execution/expression/expectation.ts b/src/webgpu/shader/execution/expression/expectation.ts
new file mode 100644
index 000000000000..8078673f2569
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/expectation.ts
@@ -0,0 +1,31 @@
+import { ROArrayArray } from '../../../../common/util/types.js';
+import { Comparator, compare } from '../../../util/compare.js';
+import { Matrix, Scalar, Value, Vector } from '../../../util/conversion.js';
+import { FPInterval } from '../../../util/floating_point.js';
+
+export type Expectation =
+ | Value
+ | FPInterval
+ | readonly FPInterval[]
+ | ROArrayArray
+ | Comparator;
+
+/** @returns if this Expectation actually a Comparator */
+export function isComparator(e: Expectation): e is Comparator {
+ return !(
+ e instanceof FPInterval ||
+ e instanceof Scalar ||
+ e instanceof Vector ||
+ e instanceof Matrix ||
+ e instanceof Array
+ );
+}
+
+/** @returns the input if it is already a Comparator, otherwise wraps it in a 'value' comparator */
+export function toComparator(input: Expectation): Comparator {
+ if (isComparator(input)) {
+ return input;
+ }
+
+ return { compare: got => compare(got, input as Value), kind: 'value' };
+}
diff --git a/src/webgpu/shader/execution/expression/expression.ts b/src/webgpu/shader/execution/expression/expression.ts
index f85516f29bdd..d59456c5596a 100644
--- a/src/webgpu/shader/execution/expression/expression.ts
+++ b/src/webgpu/shader/execution/expression/expression.ts
@@ -1,70 +1,23 @@
import { globalTestConfig } from '../../../../common/framework/test_config.js';
-import { ROArrayArray } from '../../../../common/util/types.js';
import { assert, objectEquals, unreachable } from '../../../../common/util/util.js';
import { GPUTest } from '../../../gpu_test.js';
-import { compare, Comparator, ComparatorImpl } from '../../../util/compare.js';
+import { Comparator, ComparatorImpl } from '../../../util/compare.js';
import { kValue } from '../../../util/constants.js';
import {
- ScalarType,
+ MatrixType,
Scalar,
+ ScalarType,
Type,
- TypeVec,
TypeU32,
+ TypeVec,
Value,
Vector,
VectorType,
- u32,
- i32,
- Matrix,
- MatrixType,
- ScalarBuilder,
scalarTypeOf,
} from '../../../util/conversion.js';
-import { FPInterval } from '../../../util/floating_point.js';
-import {
- cartesianProduct,
- QuantizeFunc,
- quantizeToI32,
- quantizeToU32,
-} from '../../../util/math.js';
-
-export type Expectation =
- | Value
- | FPInterval
- | readonly FPInterval[]
- | ROArrayArray
- | Comparator;
-
-/** @returns if this Expectation actually a Comparator */
-export function isComparator(e: Expectation): e is Comparator {
- return !(
- e instanceof FPInterval ||
- e instanceof Scalar ||
- e instanceof Vector ||
- e instanceof Matrix ||
- e instanceof Array
- );
-}
-/** @returns the input if it is already a Comparator, otherwise wraps it in a 'value' comparator */
-export function toComparator(input: Expectation): Comparator {
- if (isComparator(input)) {
- return input;
- }
-
- return { compare: got => compare(got, input as Value), kind: 'value' };
-}
-
-/** Case is a single expression test case. */
-export type Case = {
- // The input value(s)
- input: Value | ReadonlyArray;
- // The expected result, or function to check the result
- expected: Expectation;
-};
-
-/** CaseList is a list of Cases */
-export type CaseList = Array;
+import { Case, CaseList } from './case.js';
+import { toComparator } from './expectation.js';
/** The input value source */
export type InputSource =
@@ -1199,238 +1152,3 @@ function packScalarsToVector(
resultType: packedResultType,
};
}
-
-/**
- * Indicates bounds that acceptance intervals need to be within to avoid inputs
- * being filtered out. This is used for const-eval tests, since going OOB will
- * cause a validation error not an execution error.
- */
-export type IntervalFilter =
- | 'finite' // Expected to be finite in the interval numeric space
- | 'unfiltered'; // No expectations
-
-/**
- * A function that performs a binary operation on x and y, and returns the expected
- * result.
- */
-export interface BinaryOp {
- (x: number, y: number): number | undefined;
-}
-
-/**
- * @returns array of Case for the input params with op applied
- * @param param0s array of inputs to try for the first param
- * @param param1s array of inputs to try for the second param
- * @param op callback called on each pair of inputs to produce each case
- * @param quantize function to quantize all values
- * @param scalarize function to convert numbers to Scalars
- */
-function generateScalarBinaryToScalarCases(
- param0s: readonly number[],
- param1s: readonly number[],
- op: BinaryOp,
- quantize: QuantizeFunc,
- scalarize: ScalarBuilder
-): Case[] {
- param0s = param0s.map(quantize);
- param1s = param1s.map(quantize);
- return cartesianProduct(param0s, param1s).reduce((cases, e) => {
- const expected = op(e[0], e[1]);
- if (expected !== undefined) {
- cases.push({ input: [scalarize(e[0]), scalarize(e[1])], expected: scalarize(expected) });
- }
- return cases;
- }, new Array());
-}
-
-/**
- * @returns an array of Cases for operations over a range of inputs
- * @param param0s array of inputs to try for the first param
- * @param param1s array of inputs to try for the second param
- * @param op callback called on each pair of inputs to produce each case
- */
-export function generateBinaryToI32Cases(
- param0s: readonly number[],
- param1s: readonly number[],
- op: BinaryOp
-) {
- return generateScalarBinaryToScalarCases(param0s, param1s, op, quantizeToI32, i32);
-}
-
-/**
- * @returns an array of Cases for operations over a range of inputs
- * @param param0s array of inputs to try for the first param
- * @param param1s array of inputs to try for the second param
- * @param op callback called on each pair of inputs to produce each case
- */
-export function generateBinaryToU32Cases(
- param0s: readonly number[],
- param1s: readonly number[],
- op: BinaryOp
-) {
- return generateScalarBinaryToScalarCases(param0s, param1s, op, quantizeToU32, u32);
-}
-
-/**
- * @returns a Case for the input params with op applied
- * @param scalar scalar param
- * @param vector vector param (2, 3, or 4 elements)
- * @param op the op to apply to scalar and vector
- * @param quantize function to quantize all values in vectors and scalars
- * @param scalarize function to convert numbers to Scalars
- */
-function makeScalarVectorBinaryToVectorCase(
- scalar: number,
- vector: readonly number[],
- op: BinaryOp,
- quantize: QuantizeFunc,
- scalarize: ScalarBuilder
-): Case | undefined {
- scalar = quantize(scalar);
- vector = vector.map(quantize);
- const result = vector.map(v => op(scalar, v));
- if (result.includes(undefined)) {
- return undefined;
- }
- return {
- input: [scalarize(scalar), new Vector(vector.map(scalarize))],
- expected: new Vector((result as readonly number[]).map(scalarize)),
- };
-}
-
-/**
- * @returns array of Case for the input params with op applied
- * @param scalars array of scalar params
- * @param vectors array of vector params (2, 3, or 4 elements)
- * @param op the op to apply to each pair of scalar and vector
- * @param quantize function to quantize all values in vectors and scalars
- * @param scalarize function to convert numbers to Scalars
- */
-function generateScalarVectorBinaryToVectorCases(
- scalars: readonly number[],
- vectors: ROArrayArray,
- op: BinaryOp,
- quantize: QuantizeFunc,
- scalarize: ScalarBuilder
-): Case[] {
- const cases = new Array();
- scalars.forEach(s => {
- vectors.forEach(v => {
- const c = makeScalarVectorBinaryToVectorCase(s, v, op, quantize, scalarize);
- if (c !== undefined) {
- cases.push(c);
- }
- });
- });
- return cases;
-}
-
-/**
- * @returns a Case for the input params with op applied
- * @param vector vector param (2, 3, or 4 elements)
- * @param scalar scalar param
- * @param op the op to apply to vector and scalar
- * @param quantize function to quantize all values in vectors and scalars
- * @param scalarize function to convert numbers to Scalars
- */
-function makeVectorScalarBinaryToVectorCase(
- vector: readonly number[],
- scalar: number,
- op: BinaryOp,
- quantize: QuantizeFunc,
- scalarize: ScalarBuilder
-): Case | undefined {
- vector = vector.map(quantize);
- scalar = quantize(scalar);
- const result = vector.map(v => op(v, scalar));
- if (result.includes(undefined)) {
- return undefined;
- }
- return {
- input: [new Vector(vector.map(scalarize)), scalarize(scalar)],
- expected: new Vector((result as readonly number[]).map(scalarize)),
- };
-}
-
-/**
- * @returns array of Case for the input params with op applied
- * @param vectors array of vector params (2, 3, or 4 elements)
- * @param scalars array of scalar params
- * @param op the op to apply to each pair of vector and scalar
- * @param quantize function to quantize all values in vectors and scalars
- * @param scalarize function to convert numbers to Scalars
- */
-function generateVectorScalarBinaryToVectorCases(
- vectors: ROArrayArray,
- scalars: readonly number[],
- op: BinaryOp,
- quantize: QuantizeFunc,
- scalarize: ScalarBuilder
-): Case[] {
- const cases = new Array();
- scalars.forEach(s => {
- vectors.forEach(v => {
- const c = makeVectorScalarBinaryToVectorCase(v, s, op, quantize, scalarize);
- if (c !== undefined) {
- cases.push(c);
- }
- });
- });
- return cases;
-}
-
-/**
- * @returns array of Case for the input params with op applied
- * @param scalars array of scalar params
- * @param vectors array of vector params (2, 3, or 4 elements)
- * @param op he op to apply to each pair of scalar and vector
- */
-export function generateU32VectorBinaryToVectorCases(
- scalars: readonly number[],
- vectors: ROArrayArray,
- op: BinaryOp
-): Case[] {
- return generateScalarVectorBinaryToVectorCases(scalars, vectors, op, quantizeToU32, u32);
-}
-
-/**
- * @returns array of Case for the input params with op applied
- * @param vectors array of vector params (2, 3, or 4 elements)
- * @param scalars array of scalar params
- * @param op he op to apply to each pair of vector and scalar
- */
-export function generateVectorU32BinaryToVectorCases(
- vectors: ROArrayArray,
- scalars: readonly number[],
- op: BinaryOp
-): Case[] {
- return generateVectorScalarBinaryToVectorCases(vectors, scalars, op, quantizeToU32, u32);
-}
-
-/**
- * @returns array of Case for the input params with op applied
- * @param scalars array of scalar params
- * @param vectors array of vector params (2, 3, or 4 elements)
- * @param op he op to apply to each pair of scalar and vector
- */
-export function generateI32VectorBinaryToVectorCases(
- scalars: readonly number[],
- vectors: ROArrayArray,
- op: BinaryOp
-): Case[] {
- return generateScalarVectorBinaryToVectorCases(scalars, vectors, op, quantizeToI32, i32);
-}
-
-/**
- * @returns array of Case for the input params with op applied
- * @param vectors array of vector params (2, 3, or 4 elements)
- * @param scalars array of scalar params
- * @param op he op to apply to each pair of vector and scalar
- */
-export function generateVectorI32BinaryToVectorCases(
- vectors: ROArrayArray,
- scalars: readonly number[],
- op: BinaryOp
-): Case[] {
- return generateVectorScalarBinaryToVectorCases(vectors, scalars, op, quantizeToI32, i32);
-}
diff --git a/src/webgpu/shader/execution/expression/interval_filter.ts b/src/webgpu/shader/execution/expression/interval_filter.ts
new file mode 100644
index 000000000000..7471247e54ad
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/interval_filter.ts
@@ -0,0 +1,8 @@
+/**
+ * Indicates bounds that acceptance intervals need to be within to avoid inputs
+ * being filtered out. This is used for const-eval tests, since going OOB will
+ * cause a validation error not an execution error.
+ */
+export type IntervalFilter =
+ | 'finite' // Expected to be finite in the interval numeric space
+ | 'unfiltered'; // No expectations
diff --git a/src/webgpu/shader/execution/expression/unary/af_arithmetic.cache.ts b/src/webgpu/shader/execution/expression/unary/af_arithmetic.cache.ts
new file mode 100644
index 000000000000..4f274e892217
--- /dev/null
+++ b/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/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts
index 1ab64eb62d51..ef148833eb17 100644
--- a/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts
+++ b/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts
@@ -5,25 +5,13 @@ Execution Tests for 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 { scalarF64Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
import { onlyConstInputSource, run } from '../expression.js';
+import { d } from './af_arithmetic.cache.js';
import { abstractUnary } from './unary.js';
export const g = makeTestGroup(GPUTest);
-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
- );
- },
-});
-
g.test('negation')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation')
.desc(
diff --git a/src/webgpu/shader/execution/expression/unary/af_assignment.cache.ts b/src/webgpu/shader/execution/expression/unary/af_assignment.cache.ts
new file mode 100644
index 000000000000..7c607927fe54
--- /dev/null
+++ b/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/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts b/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts
index d59649bbd40a..76e96fe80354 100644
--- a/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts
+++ b/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts
@@ -4,24 +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 {
- limitedScalarF64Range,
- scalarF64Range,
- isSubnormalNumberF64,
-} from '../../../../util/math.js';
-import { reinterpretU64AsF64 } from '../../../../util/reinterpret.js';
-import { makeCaseCache } from '../case_cache.js';
+import { TypeAbstractFloat, TypeF16, TypeF32 } 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}`);
}
@@ -32,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
- ...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) };
- });
- },
-});
-
g.test('abstract')
.specURL('https://www.w3.org/TR/WGSL/#floating-point-conversion')
.desc(
diff --git a/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts b/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts
new file mode 100644
index 000000000000..f64ec1cd4180
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts
@@ -0,0 +1,54 @@
+import { anyOf } from '../../../../util/compare.js';
+import { Scalar, 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: Scalar[] = [];
+ 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: Scalar[] = [];
+ if (f !== 0) {
+ expected.push(bool(true));
+ }
+ if (isSubnormalNumberF16(f)) {
+ expected.push(bool(false));
+ }
+ return { input: f16(f), expected: anyOf(...expected) };
+ });
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts b/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts
index 2d83a389cd49..5f5bb31397a3 100644
--- a/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts
+++ b/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 {
- scalarF32Range,
- scalarF16Range,
- fullI32Range,
- fullU32Range,
- isSubnormalNumberF32,
- isSubnormalNumberF16,
-} from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, run, ShaderBuilder } from '../expression.js';
+import { TypeBool, TypeF16, TypeF32, TypeI32, TypeU32 } 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 scalarF32Range().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 scalarF16Range().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}`);
diff --git a/src/webgpu/shader/execution/expression/unary/f16_arithmetic.cache.ts b/src/webgpu/shader/execution/expression/unary/f16_arithmetic.cache.ts
new file mode 100644
index 000000000000..7d9ee35eec00
--- /dev/null
+++ b/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/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts
index e96bb354db8f..60e16e645221 100644
--- a/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts
+++ b/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts
@@ -5,25 +5,13 @@ 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 { scalarF16Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.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(
- scalarF16Range({ 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(
diff --git a/src/webgpu/shader/execution/expression/unary/f16_conversion.cache.ts b/src/webgpu/shader/execution/expression/unary/f16_conversion.cache.ts
new file mode 100644
index 000000000000..73d0d94c461a
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/unary/f16_conversion.cache.ts
@@ -0,0 +1,109 @@
+import { bool, f16, i32, u32 } from '../../../../util/conversion.js';
+import { FP, FPInterval } from '../../../../util/floating_point.js';
+import {
+ fullI32Range,
+ fullU32Range,
+ scalarF16Range,
+ scalarF32Range,
+ sparseMatrixF16Range,
+ sparseMatrixF32Range,
+} from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+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(
+ [...scalarF32Range(), 65535.996, -65535.996],
+ 'unfiltered',
+ FP.f16.correctlyRoundedInterval
+ );
+ },
+ f32_const: () => {
+ return FP.f32.generateScalarToIntervalCases(
+ [...scalarF32Range(), 65535.996, -65535.996],
+ 'finite',
+ FP.f16.correctlyRoundedInterval
+ );
+ },
+ // All f16 values are exactly representable in f16.
+ f16: () => {
+ return scalarF16Range().map(f => {
+ return { input: f16(f), expected: FP.f16.correctlyRoundedInterval(f) };
+ });
+ },
+ ...f32_mat_cases,
+ ...f16_mat_cases,
+});
diff --git a/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts b/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts
index a4ebeef5fe18..a8da8ff3bd7f 100644
--- a/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts
+++ b/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts
@@ -5,131 +5,20 @@ 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,
+ TypeF32,
TypeI32,
TypeMat,
TypeU32,
- u32,
} from '../../../../util/conversion.js';
-import { FP, FPInterval } from '../../../../util/floating_point.js';
-import {
- scalarF32Range,
- scalarF16Range,
- fullI32Range,
- fullU32Range,
- sparseMatrixF32Range,
- sparseMatrixF16Range,
-} from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, run, ShaderBuilder } from '../expression.js';
+import { ShaderBuilder, allInputSources, run } 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(
- [...scalarF32Range(), 65535.996, -65535.996],
- 'unfiltered',
- FP.f16.correctlyRoundedInterval
- );
- },
- f32_const: () => {
- return FP.f32.generateScalarToIntervalCases(
- [...scalarF32Range(), 65535.996, -65535.996],
- 'finite',
- FP.f16.correctlyRoundedInterval
- );
- },
- // All f16 values are exactly representable in f16.
- f16: () => {
- return scalarF16Range().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}`);
diff --git a/src/webgpu/shader/execution/expression/unary/f32_arithmetic.cache.ts b/src/webgpu/shader/execution/expression/unary/f32_arithmetic.cache.ts
new file mode 100644
index 000000000000..b23ed3216bfa
--- /dev/null
+++ b/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/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts
index 305a7812dd13..c60e2c3d51b0 100644
--- a/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts
+++ b/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts
@@ -5,25 +5,13 @@ 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 { scalarF32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.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(
- scalarF32Range({ 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(
diff --git a/src/webgpu/shader/execution/expression/unary/f32_conversion.cache.ts b/src/webgpu/shader/execution/expression/unary/f32_conversion.cache.ts
new file mode 100644
index 000000000000..f61435f07ce4
--- /dev/null
+++ b/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/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts b/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts
index 1aa0b3e4a51c..3e2fbd540ace 100644
--- a/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts
+++ b/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts
@@ -5,102 +5,20 @@ 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,
+ TypeF32,
TypeI32,
TypeMat,
TypeU32,
- u32,
} from '../../../../util/conversion.js';
-import { FP } from '../../../../util/floating_point.js';
-import {
- scalarF32Range,
- scalarF16Range,
- fullI32Range,
- fullU32Range,
- sparseMatrixF32Range,
- sparseMatrixF16Range,
-} from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
-import { allInputSources, run, ShaderBuilder } from '../expression.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 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,
-});
-
/** 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}`);
diff --git a/src/webgpu/shader/execution/expression/unary/i32_arithmetic.cache.ts b/src/webgpu/shader/execution/expression/unary/i32_arithmetic.cache.ts
new file mode 100644
index 000000000000..b7206bcf451a
--- /dev/null
+++ b/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/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts
index 14519b89675b..a6fe77ada165 100644
--- a/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts
+++ b/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 { TypeI32 } 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(
diff --git a/src/webgpu/shader/execution/expression/unary/i32_complement.cache.ts b/src/webgpu/shader/execution/expression/unary/i32_complement.cache.ts
new file mode 100644
index 000000000000..2ae18e68fe36
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/unary/i32_complement.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_complement', {
+ complement: () => {
+ return fullI32Range().map(e => {
+ return { input: i32(e), expected: i32(~e) };
+ });
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts b/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts
index e8bda51b51a9..0555da133279 100644
--- a/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts
+++ b/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 { fullI32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
+import { TypeI32 } from '../../../../util/conversion.js';
import { allInputSources, run } from '../expression.js';
+import { d } from './i32_complement.cache.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(
diff --git a/src/webgpu/shader/execution/expression/unary/i32_conversion.cache.ts b/src/webgpu/shader/execution/expression/unary/i32_conversion.cache.ts
new file mode 100644
index 000000000000..aea80176cc40
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/unary/i32_conversion.cache.ts
@@ -0,0 +1,81 @@
+import { kValue } from '../../../../util/constants.js';
+import { bool, f16, f32, i32, u32 } from '../../../../util/conversion.js';
+import {
+ fullI32Range,
+ fullU32Range,
+ quantizeToF16,
+ quantizeToF32,
+ scalarF16Range,
+ scalarF32Range,
+} 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) },
+ ];
+ },
+ 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 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/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts b/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts
index 92379f22c9cf..4ad3c4e7424f 100644
--- a/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts
+++ b/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 {
- scalarF32Range,
- scalarF16Range,
- 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 { TypeBool, TypeF16, TypeF32, TypeI32, TypeU32 } from '../../../../util/conversion.js';
+import { ShaderBuilder, allInputSources, run } 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 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)) };
- });
- },
-});
-
/** 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}`);
diff --git a/src/webgpu/shader/execution/expression/unary/u32_complement.cache.ts b/src/webgpu/shader/execution/expression/unary/u32_complement.cache.ts
new file mode 100644
index 000000000000..67e38b42a9cf
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/unary/u32_complement.cache.ts
@@ -0,0 +1,11 @@
+import { u32 } from '../../../../util/conversion.js';
+import { fullU32Range } from '../../../../util/math.js';
+import { makeCaseCache } from '../case_cache.js';
+
+export const d = makeCaseCache('unary/u32_complement', {
+ complement: () => {
+ return fullU32Range().map(e => {
+ return { input: u32(e), expected: u32(~e) };
+ });
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts b/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts
index 446e0918bd18..f5f859054724 100644
--- a/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts
+++ b/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 { fullU32Range } from '../../../../util/math.js';
-import { makeCaseCache } from '../case_cache.js';
+import { TypeU32 } from '../../../../util/conversion.js';
import { allInputSources, run } from '../expression.js';
+import { d } from './u32_complement.cache.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(
diff --git a/src/webgpu/shader/execution/expression/unary/u32_conversion.cache.ts b/src/webgpu/shader/execution/expression/unary/u32_conversion.cache.ts
new file mode 100644
index 000000000000..0187415999b8
--- /dev/null
+++ b/src/webgpu/shader/execution/expression/unary/u32_conversion.cache.ts
@@ -0,0 +1,77 @@
+import { kValue } from '../../../../util/constants.js';
+import { bool, f16, f32, i32, u32 } from '../../../../util/conversion.js';
+import {
+ fullI32Range,
+ fullU32Range,
+ quantizeToF16,
+ quantizeToF32,
+ scalarF16Range,
+ scalarF32Range,
+} 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) },
+ ];
+ },
+ 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 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 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 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 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)) };
+ });
+ },
+});
diff --git a/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts b/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts
index c469f262c93d..d684824362cf 100644
--- a/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts
+++ b/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 {
- scalarF32Range,
- scalarF16Range,
- 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 { TypeBool, TypeF16, TypeF32, TypeI32, TypeU32 } from '../../../../util/conversion.js';
+import { ShaderBuilder, allInputSources, run } 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 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 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 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 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}`);
diff --git a/src/webgpu/util/compare.ts b/src/webgpu/util/compare.ts
index 45599d25f63c..95573e6ceae2 100644
--- a/src/webgpu/util/compare.ts
+++ b/src/webgpu/util/compare.ts
@@ -5,7 +5,7 @@ import {
deserializeExpectation,
serializeExpectation,
} from '../shader/execution/expression/case_cache.js';
-import { Expectation, toComparator } from '../shader/execution/expression/expression.js';
+import { Expectation, toComparator } from '../shader/execution/expression/expectation.js';
import BinaryStream from './binary_stream.js';
import { isFloatValue, Matrix, Scalar, Value, Vector } from './conversion.js';
diff --git a/src/webgpu/util/device_pool.ts b/src/webgpu/util/device_pool.ts
index 1e6c0402cb8f..4e45aac76bb8 100644
--- a/src/webgpu/util/device_pool.ts
+++ b/src/webgpu/util/device_pool.ts
@@ -9,6 +9,9 @@ import {
} from '../../common/util/util.js';
import { getDefaultLimits, kLimits } from '../capability_info.js';
+// MUST_NOT_BE_IMPORTED_BY_DATA_CACHE
+// This file should not be transitively imported by .cache.ts files
+
export interface DeviceProvider {
readonly device: GPUDevice;
expectDeviceLost(reason: GPUDeviceLostReason): void;
diff --git a/src/webgpu/util/floating_point.ts b/src/webgpu/util/floating_point.ts
index 5dcc11e828d2..ed70413f28ab 100644
--- a/src/webgpu/util/floating_point.ts
+++ b/src/webgpu/util/floating_point.ts
@@ -1,7 +1,8 @@
import { ROArrayArray, ROArrayArrayArray } from '../../common/util/types.js';
import { assert, unreachable } from '../../common/util/util.js';
import { Float16Array } from '../../external/petamoriken/float16/float16.js';
-import { Case, IntervalFilter } from '../shader/execution/expression/expression.js';
+import { Case } from '../shader/execution/expression/case.js';
+import { IntervalFilter } from '../shader/execution/expression/interval_filter.js';
import BinaryStream from './binary_stream.js';
import { anyOf } from './compare.js';