summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/parse/literal.spec.ts
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/parse/literal.spec.ts')
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/parse/literal.spec.ts296
1 files changed, 296 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/parse/literal.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/parse/literal.spec.ts
new file mode 100644
index 0000000000..0c5c820040
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/parse/literal.spec.ts
@@ -0,0 +1,296 @@
+export const description = `Validation tests for literals`;
+
+import { makeTestGroup } from '../../../../common/framework/test_group.js';
+import { ShaderValidationTest } from '../shader_validation_test.js';
+
+export const g = makeTestGroup(ShaderValidationTest);
+
+g.test('bools')
+ .desc(`Test that valid bools are accepted.`)
+ .params(u => u.combine('val', ['true', 'false']).beginSubcases())
+ .fn(t => {
+ const code = `var test = ${t.params.val};`;
+ t.expectCompileResult(true, t.wrapInEntryPoint(code));
+ });
+
+const kAbstractIntNonNegative = new Set([
+ '0x123', // hex number
+ '123', // signed number, no suffix
+ '0', // zero
+ '0x3f', // hex with 'f' as last character
+ '2147483647', // max signed int
+]);
+
+const kAbstractIntNegative = new Set([
+ '-0x123', // hex number
+ '-123', // signed number, no suffix
+ '-0x3f', // hex with 'f' as last character
+ '-2147483647', // nagative of max signed int
+ '-2147483648', // min signed int
+]);
+
+const kI32 = new Set([
+ '94i', // signed number
+ '2147483647i', // max signed int
+ '-2147483647i', // min parsable signed int
+ 'i32(-2147483648)', // min signed int
+]);
+
+const kU32 = new Set([
+ '42u', // unsigned number
+ '0u', // min unsigned int
+ '4294967295u', // max unsigned int
+]);
+
+{
+ const kValidIntegers = new Set([
+ ...kAbstractIntNonNegative,
+ ...kAbstractIntNegative,
+ ...kI32,
+ ...kU32,
+ ]);
+ const kInvalidIntegers = new Set([
+ '0123', // Integer does not start with zero
+ '2147483648i', // max signed int + 1
+ '-2147483649i', // min signed int - 1
+ '4294967295', // a untyped lhs will be i32, so this is too big
+ '4294967295i', // max unsigned int with i suffix
+ '4294967296u', // max unsigned int + 1
+ '-1u', // negative unsigned
+ ]);
+ g.test('abstract_int')
+ .desc(`Test that valid integers are accepted, and invalid integers are rejected.`)
+ .params(u =>
+ u.combine('val', new Set([...kValidIntegers, ...kInvalidIntegers])).beginSubcases()
+ )
+ .fn(t => {
+ const code = `var test = ${t.params.val};`;
+ t.expectCompileResult(kValidIntegers.has(t.params.val), t.wrapInEntryPoint(code));
+ });
+}
+
+{
+ const kValidI32 = new Set([...kAbstractIntNonNegative, ...kAbstractIntNegative, ...kI32]);
+ const kInvalidI32 = new Set([
+ ...kU32,
+ '2147483648', // max signed int + 1
+ '2147483648i', // max signed int + 1
+ '-2147483649', // min signed int - 1
+ '-2147483649i', // min signed int - 1
+ '1.0', // no conversion from float
+ '1.0f', // no conversion from float
+ '1.0h', // no conversion from float
+ ]);
+ g.test('i32')
+ .desc(`Test that valid signed integers are accepted, and invalid signed integers are rejected.`)
+ .params(u => u.combine('val', new Set([...kValidI32, ...kInvalidI32])).beginSubcases())
+ .beforeAllSubcases(t => {
+ if (t.params.val.includes('h')) {
+ t.selectDeviceOrSkipTestCase('shader-f16');
+ }
+ })
+ .fn(t => {
+ const { val } = t.params;
+ const code = `var test: i32 = ${val};`;
+ const extensionList = val.includes('h') ? ['f16'] : [];
+ t.expectCompileResult(kValidI32.has(val), t.wrapInEntryPoint(code, extensionList));
+ });
+}
+
+{
+ const kValidU32 = new Set([
+ ...kAbstractIntNonNegative,
+ ...kU32,
+ '4294967295', // max unsigned
+ ]);
+ const kInvalidU32 = new Set([
+ ...kAbstractIntNegative,
+ ...kI32,
+ '4294967296', // max unsigned int + 1
+ '4294967296u', // min unsigned int + 1
+ '-1', // min unsigned int - 1
+ '1.0', // no conversion from float
+ '1.0f', // no conversion from float
+ '1.0h', // no conversion from float
+ ]);
+ g.test('u32')
+ .desc(
+ `Test that valid unsigned integers are accepted, and invalid unsigned integers are rejected.`
+ )
+ .params(u => u.combine('val', new Set([...kValidU32, ...kInvalidU32])).beginSubcases())
+ .beforeAllSubcases(t => {
+ if (t.params.val.includes('h')) {
+ t.selectDeviceOrSkipTestCase('shader-f16');
+ }
+ })
+ .fn(t => {
+ const { val } = t.params;
+ const code = `var test: u32 = ${val};`;
+ const extensionList = val.includes('h') ? ['f16'] : [];
+ t.expectCompileResult(kValidU32.has(val), t.wrapInEntryPoint(code, extensionList));
+ });
+}
+
+const kF32 = new Set([
+ '0f', // Zero float
+ '0.0f', // Zero float
+ '12.223f', // float value
+ '12.f', // .f
+ '.12f', // No leading number with a f
+ '2.4e+4f', // Positive exponent with f suffix
+ '2.4e-2f', // Negative exponent with f suffix
+ '2.e+4f', // Exponent without decimals
+ '1e-4f', // Exponennt without decimal point
+ '0x1P+4f', // Hex float no decimal
+]);
+
+const kF16 = new Set([
+ '0h', // Zero half
+ '1h', // Half no decimal
+ '.1h', // Half no leading value
+ '1.1e2h', // Exponent half no sign
+ '1.1E+2h', // Exponent half, plus (uppercase E)
+ '2.4e-2h', // Exponent half, negative
+ '0xep2h', // Hexfloat half lower case p
+ '0xEp-2h', // Hexfloat uppcase hex value
+ '0x3p+2h', // Hex float half positive exponent
+ '0x3.2p+2h', // Hex float with decimal half
+]);
+
+const kAbstractFloat = new Set([
+ '0.0', // Zero float without suffix
+ '.0', // Zero float without leading value
+ '12.', // No decimal points
+ '00012.', // Leading zeros allowed
+ '.12', // No leading digits
+ '1.2e2', // Exponent without sign (lowercase e)
+ '1.2E2', // Exponent without sign (uppercase e)
+ '1.2e+2', // positive exponent
+ '2.4e-2', // Negative exponent
+ '.1e-2', // Exponent without leading number
+ '0x.3', // Hex float, lowercase X
+ '0X.3', // Hex float, uppercase X
+ '0xa.fp+2', // Hex float, lowercase p
+ '0xa.fP+2', // Hex float, uppercase p
+ '0xE.fp+2', // Uppercase E (as hex, but matches non hex exponent char)
+ '0X1.fp-4', // Hex float negative exponent
+]);
+
+{
+ const kValidFloats = new Set([...kF32, ...kF16, ...kAbstractFloat]);
+ const kInvalidFloats = new Set([
+ '.f', // Must have a number
+ '.e-2', // Exponent without leading values
+ '1.e&2f', // Exponent invalid sign
+ '1.ef', // Exponent without value
+ '1.e+f', // Exponent sign no value
+ '0x.p2', // Hex float no value
+ '0x1p', // Hex float missing exponent
+ '0x1p^', // Hex float invalid exponent
+ '1.0e+999999999999f', // Too big
+ '0x1.0p+999999999999f', // Too big hex
+ '0x1.00000001pf0', // Mantissa too big
+ ]);
+ const kInvalidF16s = new Set([
+ '1.1eh', // Missing exponent value
+ '1.1e%2h', // Invalid exponent sign
+ '1.1e+h', // Missing exponent with sign
+ '1.0e+999999h', // Too large
+ '0x1.0p+999999h', // Too large hex
+ '0xf.h', // Having suffix "h" without "p" or "P"
+ '0x3h', // Having suffix "h" without "p" or "P"
+ ]);
+
+ g.test('abstract_float')
+ .desc(`Test that valid floats are accepted, and invalid floats are rejected`)
+ .params(u =>
+ u
+ .combine('val', new Set([...kValidFloats, ...kInvalidFloats, ...kInvalidF16s]))
+ .beginSubcases()
+ )
+ .beforeAllSubcases(t => {
+ if (kF16.has(t.params.val) || kInvalidF16s.has(t.params.val)) {
+ t.selectDeviceOrSkipTestCase('shader-f16');
+ }
+ })
+ .fn(t => {
+ const code = `var test = ${t.params.val};`;
+ const extensionList = kF16.has(t.params.val) || kInvalidF16s.has(t.params.val) ? ['f16'] : [];
+ t.expectCompileResult(
+ kValidFloats.has(t.params.val),
+ t.wrapInEntryPoint(code, extensionList)
+ );
+ });
+}
+
+{
+ const kValidF32 = new Set([
+ ...kF32,
+ ...kAbstractFloat,
+ '1', // AbstractInt
+ '-1', // AbstractInt
+ ]);
+ const kInvalidF32 = new Set([
+ ...kF16, // no conversion
+ '1u', // unsigned
+ '1i', // signed
+ '1h', // half float
+ '.f', // Must have a number
+ '.e-2', // Exponent without leading values
+ '1.e&2f', // Exponent invalid sign
+ '1.ef', // Exponent without value
+ '1.e+f', // Exponent sign no value
+ '0x.p2', // Hex float no value
+ '0x1p', // Hex float missing exponent
+ '0x1p^', // Hex float invalid exponent
+ '1.0e+999999999999f', // Too big
+ '0x1.0p+999999999999f', // Too big hex
+ '0x1.00000001pf0', // Mantissa too big
+ ]);
+
+ g.test('f32')
+ .desc(`Test that valid floats are accepted, and invalid floats are rejected`)
+ .params(u => u.combine('val', new Set([...kValidF32, ...kInvalidF32])).beginSubcases())
+ .beforeAllSubcases(t => {
+ if (kF16.has(t.params.val)) {
+ t.selectDeviceOrSkipTestCase('shader-f16');
+ }
+ })
+ .fn(t => {
+ const { val } = t.params;
+ const code = `var test: f32 = ${val};`;
+ const extensionList = kF16.has(val) ? ['f16'] : [];
+ t.expectCompileResult(kValidF32.has(val), t.wrapInEntryPoint(code, extensionList));
+ });
+}
+
+{
+ const kValidF16 = new Set([
+ ...kF16,
+ ...kAbstractFloat,
+ '1', // AbstractInt
+ '-1', // AbstractInt
+ ]);
+ const kInvalidF16 = new Set([
+ ...kF32,
+ '1i', // signed int
+ '1u', // unsigned int
+ '1f', // no conversion from f32 to f16
+ '1.1eh', // Missing exponent value
+ '1.1e%2h', // Invalid exponent sign
+ '1.1e+h', // Missing exponent with sign
+ '1.0e+999999h', // Too large
+ '0x1.0p+999999h', // Too large hex
+ ]);
+
+ g.test('f16')
+ .desc(
+ `
+Test that valid half floats are accepted, and invalid half floats are rejected
+
+TODO: Need to inject the 'enable fp16' into the shader to enable the parsing.
+`
+ )
+ .params(u => u.combine('val', new Set([...kValidF16, ...kInvalidF16])).beginSubcases())
+ .unimplemented();
+}