Tools/ChangeLog

 12018-08-22 Myles C. Maxfield <mmaxfield@apple.com>
 2
 3 [WHLSL] Allow native types to have type arguments (like "vector<float, 4>")
 4 https://bugs.webkit.org/show_bug.cgi?id=188773
 5
 6 Previously, the way to identify a type was strictly by name, which was represented by a string. Therefore, when something like
 7 "vector<int, 3>" was parsed, it would produce a TypeRef with the name "vector" and typeArguments [TypeRef, IntLiteral]. Then,
 8 there was a pass to convert the TypeRef to have the name "int3" and no typeArguments. After this transformation, each type can
 9 be uniquely identified by name.
 10
 11 This is okay for vectors and matrices, but it is unfortunate for textures (e.g. Texture2D<float4>) because they don't have any
 12 natural string-only name. In addition, the canonicalization would have to be made aware of the fact that Texture2D<float4> is
 13 the same as Texture2D<vector<float, 4>>. Similarly, an author may wish to typedef float4 to a different name.
 14
 15 It would be possible to mangle the names of the texture types to something unique, but then we lose information about the inner
 16 type. For example, if we did this, Visitor wouldn't recurse into the float4 when encountering Texture2D<float4> because that
 17 information would be lost. This could potentially make operations like programWithUnnecessaryThingsRemoved() more difficult to
 18 implement in the future.
 19
 20 So, it would be better to have each type uniquely identified by (name, typeArguments). TypeRef will therefore also have
 21 typeArguments which are used to determine which type it is referencing. After this analysis is done to determine what each
 22 TypeRef is referencing, subsequent passes shouldn't care about the typeArguments and should only care about the .type field
 23 which had been set - this was true even before this patch.
 24
 25 Reviewed by NOBODY (OOPS!).
 26
 27 * WebGPUShadingLanguageRI/All.js:
 28 * WebGPUShadingLanguageRI/CallExpression.js:
 29 (CallExpression.prototype.resolve):
 30 * WebGPUShadingLanguageRI/CheckTypesWithArguments.js: Copied from Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js.
 31 (checkTypesWithArguments.TypeWithArgumentsChecker.prototype.visitTypeRef):
 32 (checkTypesWithArguments.TypeWithArgumentsChecker):
 33 (checkTypesWithArguments):
 34 * WebGPUShadingLanguageRI/Checker.js:
 35 (Checker.prototype.visitProgram):
 36 (Checker.prototype.visitTypeRef):
 37 * WebGPUShadingLanguageRI/InferTypesForCall.js:
 38 (inferTypesForCall):
 39 (inferTypesForTypeArguments):
 40 * WebGPUShadingLanguageRI/Intrinsics.js:
 41 (Intrinsics.cast):
 42 (Intrinsics.bitwiseCast):
 43 (Intrinsics.castToHalf):
 44 (Intrinsics.):
 45 (Intrinsics):
 46 * WebGPUShadingLanguageRI/NameContext.js:
 47 (NameContext.prototype.add):
 48 (NameContext.prototype.get let):
 49 (NameContext.underlyingThings.prototype.else):
 50 (NameContext.prototype.Symbol.iterator):
 51 (NameContext):
 52 * WebGPUShadingLanguageRI/NameResolver.js:
 53 (NameResolver.prototype.visitTypeRef):
 54 (NameResolver.prototype.visitCallExpression):
 55 (NameResolver):
 56 (NameResolver.prototype.visitVectorType): Deleted.
 57 * WebGPUShadingLanguageRI/NativeType.js:
 58 (NativeType):
 59 (NativeType.prototype.get typeArguments):
 60 (NativeType.prototype.toString):
 61 (NativeType.create):
 62 * WebGPUShadingLanguageRI/Prepare.js:
 63 (let.prepare):
 64 * WebGPUShadingLanguageRI/Program.js:
 65 (Program.prototype.add):
 66 (Program.prototype.toString):
 67 (Program):
 68 * WebGPUShadingLanguageRI/RecursiveTypeChecker.js:
 69 (RecursiveTypeChecker.prototype.visitTypeRef):
 70 (RecursiveTypeChecker):
 71 * WebGPUShadingLanguageRI/RemoveTypeArguments.js: Removed.
 72 * WebGPUShadingLanguageRI/ResolveNames.js:
 73 (resolveNamesInTypes):
 74 * WebGPUShadingLanguageRI/ResolveOverloadImpl.js:
 75 * WebGPUShadingLanguageRI/ResolveTypeDefs.js:
 76 (resolveTypeDefsInTypes):
 77 * WebGPUShadingLanguageRI/Rewriter.js:
 78 (Rewriter.prototype.visitTypeRef):
 79 (Rewriter.prototype.visitVectorType):
 80 (Rewriter):
 81 * WebGPUShadingLanguageRI/SPIRV.html:
 82 * WebGPUShadingLanguageRI/StandardLibrary.js:
 83 (bool.operator):
 84 * WebGPUShadingLanguageRI/StatementCloner.js:
 85 (StatementCloner.prototype.visitNativeType):
 86 * WebGPUShadingLanguageRI/SynthesizeDefaultConstructorOperator.js:
 87 (synthesizeDefaultConstructorOperator.FindAllTypes.prototype.visitVectorType):
 88 (synthesizeDefaultConstructorOperator.FindAllTypes):
 89 (synthesizeDefaultConstructorOperator):
 90 * WebGPUShadingLanguageRI/SynthesizeStructAccessors.js:
 91 (synthesizeStructAccessors.createTypeRef):
 92 * WebGPUShadingLanguageRI/Test.html:
 93 * WebGPUShadingLanguageRI/Test.js:
 94 * WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js: Copied from Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js.
 95 (TypeOverloadResolutionFailure):
 96 (TypeOverloadResolutionFailure.prototype.get type):
 97 (TypeOverloadResolutionFailure.prototype.get reason):
 98 (TypeOverloadResolutionFailure.prototype.toString):
 99 * WebGPUShadingLanguageRI/TypeRef.js:
 100 (TypeRef):
 101 (TypeRef.wrap):
 102 (TypeRef.prototype.get possibleOverloads):
 103 (TypeRef.prototype.set possibleOverloads):
 104 (TypeRef.prototype.resolve):
 105 (TypeRef.prototype.toString):
 106 (TypeRef.instantiate): Deleted.
 107 * WebGPUShadingLanguageRI/UnificationContext.js:
 108 (UnificationContext.prototype.verify):
 109 * WebGPUShadingLanguageRI/VectorType.js:
 110 (VectorType):
 111 (VectorType.prototype.get elementType):
 112 (VectorType.prototype.get numElements):
 113 (VectorType.prototype.get numElementsValue):
 114 (VectorType.prototype.toString):
 115 * WebGPUShadingLanguageRI/Visitor.js:
 116 (Visitor.prototype.visitTypeRef):
 117 (Visitor.prototype.visitNativeType):
 118 (Visitor.prototype.visitVectorType):
 119 (Visitor):
 120 * WebGPUShadingLanguageRI/index.html:
 121
11222018-08-21 Alex Christensen <achristensen@webkit.org>
2123
3124 Roll out r235139 and r235146

Tools/WebGPUShadingLanguageRI/All.js

@@load("CheckLoops.js");
6060load("CheckRecursion.js");
6161load("CheckRecursiveTypes.js");
6262load("CheckReturns.js");
 63load("CheckTypesWithArguments.js");
6364load("CheckUnreachableCode.js");
6465load("CheckWrapped.js");
6566load("Checker.js");

@@load("PtrType.js");
133134load("ReadModifyWriteExpression.js");
134135load("RecursionChecker.js");
135136load("RecursiveTypeChecker.js");
136 load("RemoveTypeArguments.js");
137137load("ResolveNames.js");
138138load("ResolveOverloadImpl.js");
139139load("ResolveProperties.js");

@@load("TrapStatement.js");
157157load("TypeDef.js");
158158load("TypeDefResolver.js");
159159load("TypeRef.js");
 160load("TypeOverloadResolutionFailure.js");
160161load("TypedValue.js");
161162load("UintLiteral.js");
162163load("UintLiteralType.js");

@@load("WSyntaxError.js");
170171load("WTrapError.js");
171172load("WTypeError.js");
172173load("WhileLoop.js");
173 load("WrapChecker.js");
174174\ No newline at end of file
 175load("WrapChecker.js");

Tools/WebGPUShadingLanguageRI/CallExpression.js

@@class CallExpression extends Expression {
6464 overload.func = func;
6565 }
6666
67 
6867 if (!overload.func) {
6968 failures.push(...overload.failures);
7069 let message = "Did not find function named " + this.name + " for call with ";

Tools/WebGPUShadingLanguageRI/CheckTypesWithArguments.js

 1/*
 2 * Copyright (C) 2018 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25"use strict";
 26
 27function checkTypesWithArguments(program)
 28{
 29 class TypeWithArgumentsChecker extends Visitor {
 30 visitTypeRef(node)
 31 {
 32 if (node.name == "vector" && node.typeArguments.length == 0)
 33 throw new Error("Builtin type ${node.name} should always have type arguments.");
 34 }
 35 }
 36 program.visit(new TypeWithArgumentsChecker());
 37}
 38

Tools/WebGPUShadingLanguageRI/Checker.js

@@class Checker extends Visitor {
4141 statement.visit(this);
4242 }
4343
44  for (let type of node.types.values())
45  doStatement(type);
 44 for (let type of node.types.values()) {
 45 if (type instanceof Array) {
 46 for (let constituentType of type)
 47 doStatement(constituentType);
 48 } else
 49 doStatement(type);
 50 }
4651 for (let funcs of node.functions.values()) {
4752 for (let func of funcs) {
4853 this.visitFunc(func);

@@class Checker extends Visitor {
245250
246251 visitTypeRef(node)
247252 {
248  if (!node.type)
 253 super.visitTypeRef(node);
 254 if (!node.type && !node.possibleOverloads)
249255 throw new Error("Type reference without a type in checker: " + node + " at " + node.origin);
 256 if (!node.type)
 257 node.resolve(node.possibleOverloads, this._program);
 258 if (!node.type)
 259 throw new Error("Type reference without a type after possibly resolving in checker: " + node + " at " + node.origin);
 260 // All the structs will be visited by visitProgram() iterating through each top-level type.
 261 // We don't want to recurse here because the contents of structs can refer to themselves (e.g. a linked list),
 262 // and this would can an infinite loop.
 263 // Typedefs can't refer to themselves because we check that in TypeDefResolver.
250264 if (!(node.type instanceof StructType))
251265 node.type.visit(this);
252266 }

Tools/WebGPUShadingLanguageRI/InferTypesForCall.js

@@function inferTypesForCall(func, argumentTypes, returnType)
3636 if (!argumentTypes[i].unify(unificationContext, func.parameters[i].type))
3737 return {failure: new OverloadResolutionFailure(func, "Argument #" + (i + 1) + " " + (func.parameters[i].name ? "for parameter " + func.parameters[i].name + " " : "") + "does not match (passed " + argumentTypes[i] + ", require " + func.parameters[i].type + ")")};
3838 }
39  if (returnType && !returnType.unify(unificationContext, func.returnType)) {
40  if (func.returnType.toString() == "vector") {
41  returnType.unify(unificationContext, func.returnType)
42  }
 39 if (returnType && !returnType.unify(unificationContext, func.returnType))
4340 return {failure: new OverloadResolutionFailure(func, "Return type " + func.returnType + " does not match " + returnType)};
44  }
4541 let verificationResult = unificationContext.verify();
4642 if (!verificationResult.result)
4743 return {failure: new OverloadResolutionFailure(func, verificationResult.reason)};

@@function inferTypesForCall(func, argumentTypes, returnType)
4945 return {func, unificationContext};
5046}
5147
 48function inferTypesForTypeArguments(type, typeArguments)
 49{
 50 if (typeArguments.length != type.typeArguments.length)
 51 return {failure: new TypeOverloadResolutionFailure(type, "Wrong number of arguments (passed " + typeArguments.length + ", require " + type.typeArguments.length + ")")};
 52 let unificationContext = new UnificationContext();
 53
 54 for (let i = 0; i < typeArguments.length; ++i) {
 55 if (!typeArguments[i])
 56 throw new Error("Null type argument at i = " + i);
 57 if (!typeArguments[i].unify(unificationContext, type.typeArguments[i]))
 58 return {failure: new TypeOverloadResolutionFailure(type, "Argument #" + (i + 1) + " " + (type.typeArguments[i].name ? "for parameter " + type.typeArguments[i].name + " " : "") + "does not match (passed " + typeArguments[i] + ", require " + type.typeArguments[i].type + ")")};
 59 }
 60 let verificationResult = unificationContext.verify();
 61 if (!verificationResult.result)
 62 return {failure: new TypeOverloadResolutionFailure(type, verificationResult.reason)};
 63
 64 return {type, unificationContext};
 65}

Tools/WebGPUShadingLanguageRI/Intrinsics.js

@@class Intrinsics {
3333 // to catch the intrinsics must be based on the type names that StandardLibrary.js uses.
3434 // For example, if a native function is declared using "int" rather than "int", then we must
3535 // use "int" here, since we don't yet know that they are the same type.
36 
37  this._map.set(
38  "native typedef void",
39  type => {
40  this.void = type;
41  type.size = 0;
42  type.populateDefaultValue = () => { };
43  });
44 
 36
4537 function isBitwiseEquivalent(left, right)
4638 {
4739 let doubleArray = new Float64Array(1);

@@class Intrinsics {
5648 return true;
5749 }
5850
 51 function cast(typedArrayConstructor, number)
 52 {
 53 var array = new typedArrayConstructor(1);
 54 array[0] = number;
 55 return array[0];
 56 }
 57
 58 function bitwiseCast(typedArrayConstructor1, typedArrayConstructor2, value)
 59 {
 60 let typedArray1 = new typedArrayConstructor1(1);
 61 let typedArray2 = new typedArrayConstructor2(typedArray1.buffer);
 62 typedArray1[0] = value;
 63 return typedArray2[0];
 64 }
 65
 66 function castToHalf(number)
 67 {
 68 // FIXME: Make this math obey IEEE 754.
 69 if (Number.isNaN(number))
 70 return number
 71 if (number > 65504)
 72 return Number.POSITIVE_INFINITY;
 73 if (number < -65504)
 74 return Number.NEGATIVE_INFINITY;
 75 if (number > 0 && number < Math.pow(2, -24))
 76 return 0;
 77 if (number < 0 && number > -Math.pow(2, -24))
 78 return -0;
 79 let doubleArray = new Float64Array(1);
 80 let uintArray = new Uint8Array(doubleArray.buffer);
 81 doubleArray[0] = number;
 82 let sign = uintArray[7] & 0x80;
 83 let exponent = ((uintArray[7] & 0x7f) << 4) | ((uintArray[6] & 0xf0) >>> 4);
 84 let significand = ((uintArray[6] & 0x0f) << 6) | ((uintArray[5] & 0xfc) >>> 2);
 85
 86 if ((exponent - 1023) < -14) {
 87 exponent = 0;
 88 significand = (Math.abs(number) * Math.pow(2, 24)) >>> 0;
 89 let value = Math.pow(2, -14) * significand / 1024;
 90 if (sign != 0)
 91 value *= -1;
 92 return value;
 93 }
 94
 95 doubleArray[0] = 0;
 96
 97 uintArray[7] |= sign;
 98 uintArray[7] |= (exponent >>> 4);
 99 uintArray[6] |= ((exponent << 4) & 0xf0);
 100 uintArray[6] |= (significand >>> 6);
 101 uintArray[5] |= ((significand << 2) & 0xfc);
 102
 103 return doubleArray[0];
 104 }
 105
59106 this._map.set(
60  "native typedef int",
 107 "native typedef void",
61108 type => {
62  this.int = type;
63  type.isPrimitive = true;
64  type.isInt = true;
65  type.isNumber = true;
66  type.isSigned = true;
67  type.canRepresent = value => isBitwiseEquivalent(value | 0, value);
68  type.size = 1;
69  type.defaultValue = 0;
70  type.createLiteral = (origin, value) => IntLiteral.withType(origin, value | 0, type);
71  type.successorValue = value => (value + 1) | 0;
72  type.valuesEqual = (a, b) => a === b;
73  type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
74  type.formatValueFromIntLiteral = value => value | 0;
75  type.formatValueFromUintLiteral = value => value | 0;
76  type.allValues = function*() {
77  for (let i = 0; i <= 0xffffffff; ++i) {
78  let value = i | 0;
79  yield {value: value, name: value};
80  }
81  };
 109 this.void = type;
 110 type.size = 0;
 111 type.populateDefaultValue = () => { };
82112 });
83113
84114 this._map.set(
85  "native typedef uint",
 115 "native typedef bool",
86116 type => {
87  this.uint = type;
 117 this.bool = type;
88118 type.isPrimitive = true;
89  type.isInt = true;
90  type.isNumber = true;
91  type.isSigned = false;
92  type.canRepresent = value => isBitwiseEquivalent(value >>> 0, value);
93119 type.size = 1;
94  type.defaultValue = 0;
95  type.createLiteral = (origin, value) => IntLiteral.withType(origin, value >>> 0, type);
96  type.successorValue = value => (value + 1) >>> 0;
97  type.valuesEqual = (a, b) => a === b;
98  type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
99  type.formatValueFromIntLiteral = value => value >>> 0;
100  type.formatValueFromUintLiteral = value => value >>> 0;
101  type.allValues = function*() {
102  for (let i = 0; i <= 0xffffffff; ++i)
103  yield {value: i, name: i};
104  };
 120 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, false);
105121 });
106122
107123 this._map.set(
108124 "native typedef uchar",
109125 type => {
110126 this.uchar = type;
 127 type.isPrimitive = true;
111128 type.isInt = true;
112129 type.isNumber = true;
113130 type.isSigned = false;

@@class Intrinsics {
126143 };
127144 });
128145
 146
 147 this._map.set(
 148 "native typedef ushort",
 149 type => {
 150 this.ushort = type;
 151 type.isPrimitive = true;
 152 type.isInt = true;
 153 type.isNumber = true;
 154 type.isSigned = false;
 155 type.canRepresent = value => isBitwiseEquivalent(value & 0xffff, value);
 156 type.size = 1;
 157 type.defaultValue = 0;
 158 type.createLiteral = (origin, value) => IntLiteral.withType(origin, value & 0xffff, type);
 159 type.successorValue = value => (value + 1) & 0xffff;
 160 type.valuesEqual = (a, b) => a === b;
 161 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
 162 type.formatValueFromIntLiteral = value => value & 0xffff;
 163 type.formatValueFromUintLiteral = value => value & 0xffff;
 164 type.allValues = function*() {
 165 for (let i = 0; i <= 0xffff; ++i)
 166 yield {value: i, name: i};
 167 };
 168 });
 169
129170 this._map.set(
130  "native typedef float",
131  type => {
132  this.float = type;
133  type.isPrimitive = true;
134  type.size = 1;
135  type.isFloating = true;
136  type.isNumber = true;
137  type.canRepresent = value => isBitwiseEquivalent(Math.fround(value), value);
138  type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
139  type.formatValueFromIntLiteral = value => value;
140  type.formatValueFromUintLiteral = value => value;
141  type.formatValueFromFloatLiteral = value => Math.fround(value);
142  });
 171 "native typedef uint",
 172 type => {
 173 this.uint = type;
 174 type.isPrimitive = true;
 175 type.isInt = true;
 176 type.isNumber = true;
 177 type.isSigned = false;
 178 type.canRepresent = value => isBitwiseEquivalent(value >>> 0, value);
 179 type.size = 1;
 180 type.defaultValue = 0;
 181 type.createLiteral = (origin, value) => IntLiteral.withType(origin, value >>> 0, type);
 182 type.successorValue = value => (value + 1) >>> 0;
 183 type.valuesEqual = (a, b) => a === b;
 184 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
 185 type.formatValueFromIntLiteral = value => value >>> 0;
 186 type.formatValueFromUintLiteral = value => value >>> 0;
 187 type.allValues = function*() {
 188 for (let i = 0; i <= 0xffffffff; ++i)
 189 yield {value: i, name: i};
 190 };
 191 });
143192
144193 this._map.set(
145  "native typedef bool",
146  type => {
147  this.bool = type;
148  type.isPrimitive = true;
149  type.size = 1;
150  type.populateDefaultValue = (buffer, offset) => buffer.set(offset, false);
151  });
 194 "native typedef char",
 195 type => {
 196 this.char = type;
 197 type.isPrimitive = true;
 198 type.isInt = true;
 199 type.isNumber = true;
 200 type.isSigned = true;
 201 type.canRepresent = value => isBitwiseEquivalent(cast(Int8Array, value), value);
 202 type.size = 1;
 203 type.defaultValue = 0;
 204 type.createLiteral = (origin, value) => IntLiteral.withType(origin, cast(Int8Array, value), type);
 205 type.successorValue = value => cast(Int8Array, value + 1);
 206 type.valuesEqual = (a, b) => a === b;
 207 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
 208 type.formatValueFromIntLiteral = value => cast(Int8Array, value);
 209 type.formatValueFromUintLiteral = value => cast(Int8Array, value);
 210 type.allValues = function*() {
 211 for (let i = 0; i <= 0xff; ++i) {
 212 let value = cast(Int8Array, i);
 213 yield {value: value, name: value};
 214 }
 215 };
 216 });
 217
 218 this._map.set(
 219 "native typedef short",
 220 type => {
 221 this.short = type;
 222 type.isPrimitive = true;
 223 type.isInt = true;
 224 type.isNumber = true;
 225 type.isSigned = true;
 226 type.canRepresent = value => isBitwiseEquivalent(cast(Int16Array, value), value);
 227 type.size = 1;
 228 type.defaultValue = 0;
 229 type.createLiteral = (origin, value) => IntLiteral.withType(origin, cast(Int16Array, value), type);
 230 type.successorValue = value => cast(Int16Array, value + 1);
 231 type.valuesEqual = (a, b) => a === b;
 232 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
 233 type.formatValueFromIntLiteral = value => cast(Int16Array, value);
 234 type.formatValueFromUintLiteral = value => cast(Int16Array, value);
 235 type.allValues = function*() {
 236 for (let i = 0; i <= 0xffff; ++i) {
 237 let value = cast(Int16Array, i);
 238 yield {value: value, name: value};
 239 }
 240 };
 241 });
 242
 243 this._map.set(
 244 "native typedef int",
 245 type => {
 246 this.int = type;
 247 type.isPrimitive = true;
 248 type.isInt = true;
 249 type.isNumber = true;
 250 type.isSigned = true;
 251 type.canRepresent = value => isBitwiseEquivalent(value | 0, value);
 252 type.size = 1;
 253 type.defaultValue = 0;
 254 type.createLiteral = (origin, value) => IntLiteral.withType(origin, value | 0, type);
 255 type.successorValue = value => (value + 1) | 0;
 256 type.valuesEqual = (a, b) => a === b;
 257 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
 258 type.formatValueFromIntLiteral = value => value | 0;
 259 type.formatValueFromUintLiteral = value => value | 0;
 260 type.allValues = function*() {
 261 for (let i = 0; i <= 0xffffffff; ++i) {
 262 let value = i | 0;
 263 yield {value: value, name: value};
 264 }
 265 };
 266 });
 267
 268 this._map.set(
 269 "native typedef half",
 270 type => {
 271 this.half = type;
 272 type.isPrimitive = true;
 273 type.size = 1;
 274 type.isFloating = true;
 275 type.isNumber = true;
 276 type.canRepresent = value => isBitwiseEquivalent(castToHalf(value), value);
 277 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
 278 type.formatValueFromIntLiteral = value => value;
 279 type.formatValueFromUintLiteral = value => value;
 280 type.formatValueFromFloatLiteral = value => castToHalf(value);
 281 });
 282
 283 this._map.set(
 284 "native typedef float",
 285 type => {
 286 this.float = type;
 287 type.isPrimitive = true;
 288 type.size = 1;
 289 type.isFloating = true;
 290 type.isNumber = true;
 291 type.canRepresent = value => isBitwiseEquivalent(Math.fround(value), value);
 292 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
 293 type.formatValueFromIntLiteral = value => value;
 294 type.formatValueFromUintLiteral = value => value;
 295 type.formatValueFromFloatLiteral = value => Math.fround(value);
 296 });
 297
 298 this._map.set(
 299 "native typedef atomic_int",
 300 type => {
 301 this.atomic_int = type;
 302 });
 303
 304 this._map.set(
 305 "native typedef atomic_uint",
 306 type => {
 307 this.atomic_uint = type;
 308 });
152309
153310 for (let vectorType of VectorElementTypes) {
154  for (let vectorSize of VectorElementSizes)
155  this._map.set(`native typedef vector<${vectorType}, ${vectorSize}>`, type => {});
 311 for (let vectorSize of VectorElementSizes) {
 312 this._map.set(`native typedef vector<${vectorType}, ${vectorSize}>`, type => {
 313 this[`vector<${vectorType}, ${vectorSize}>`] = type;
 314 });
 315 }
156316 }
157 
 317
158318 this._map.set(
159319 "native operator int(uint)",
160320 func => {
161321 func.implementation = ([value]) => EPtr.box(value.loadValue() | 0);
162322 });
163 
 323
164324 this._map.set(
165325 "native operator int(uchar)",
166326 func => {
167327 func.implementation = ([value]) => EPtr.box(value.loadValue() | 0);
168328 });
169 
 329
170330 this._map.set(
171331 "native operator int(float)",
172332 func => {
173333 func.implementation = ([value]) => EPtr.box(value.loadValue() | 0);
174334 });
175 
 335
176336 this._map.set(
177337 "native operator uint(int)",
178338 func => {
179339 func.implementation = ([value]) => EPtr.box(value.loadValue() >>> 0);
180340 });
181 
 341
182342 this._map.set(
183343 "native operator uint(uchar)",
184344 func => {
185345 func.implementation = ([value]) => EPtr.box(value.loadValue() >>> 0);
186346 });
187 
 347
188348 this._map.set(
189349 "native operator uint(float)",
190350 func => {
191351 func.implementation = ([value]) => EPtr.box(value.loadValue() >>> 0);
192352 });
193 
 353
194354 this._map.set(
195355 "native operator uchar(int)",
196356 func => {
197357 func.implementation = ([value]) => EPtr.box(value.loadValue() & 0xff);
198358 });
199 
 359
200360 this._map.set(
201361 "native operator uchar(uint)",
202362 func => {
203363 func.implementation = ([value]) => EPtr.box(value.loadValue() & 0xff);
204364 });
205 
 365
206366 this._map.set(
207367 "native operator uchar(float)",
208368 func => {
209369 func.implementation = ([value]) => EPtr.box(value.loadValue() & 0xff);
210370 });
211 
 371
212372 this._map.set(
213373 "native operator float(int)",
214374 func => {
215375 func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
216376 });
217 
 377
218378 this._map.set(
219379 "native operator float(uint)",
220380 func => {
221381 func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
222382 });
223 
 383
224384 this._map.set(
225385 "native operator float(uchar)",
226386 func => {
227387 func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
228388 });
229 
 389
230390 this._map.set(
231391 "native int operator+(int,int)",
232392 func => {
233393 func.implementation = ([left, right]) =>
234394 EPtr.box((left.loadValue() + right.loadValue()) | 0);
235395 });
236 
 396
237397 this._map.set(
238398 "native uint operator+(uint,uint)",
239399 func => {
240400 func.implementation = ([left, right]) =>
241401 EPtr.box((left.loadValue() + right.loadValue()) >>> 0);
242402 });
243 
 403
244404 this._map.set(
245405 "native float operator+(float,float)",
246406 func => {
247407 func.implementation = ([left, right]) =>
248408 EPtr.box(Math.fround(left.loadValue() + right.loadValue()));
249409 });
250 
 410
251411 this._map.set(
252412 "native int operator-(int,int)",
253413 func => {
254414 func.implementation = ([left, right]) =>
255415 EPtr.box((left.loadValue() - right.loadValue()) | 0);
256416 });
257 
 417
258418 this._map.set(
259419 "native uint operator-(uint,uint)",
260420 func => {
261421 func.implementation = ([left, right]) =>
262422 EPtr.box((left.loadValue() - right.loadValue()) >>> 0);
263423 });
264 
 424
265425 this._map.set(
266426 "native float operator-(float,float)",
267427 func => {
268428 func.implementation = ([left, right]) =>
269429 EPtr.box(Math.fround(left.loadValue() - right.loadValue()));
270430 });
271 
 431
272432 this._map.set(
273433 "native int operator*(int,int)",
274434 func => {

@@class Intrinsics {
276436 return EPtr.box((left.loadValue() * right.loadValue()) | 0);
277437 };
278438 });
279 
 439
280440 this._map.set(
281441 "native uint operator*(uint,uint)",
282442 func => {
283443 func.implementation = ([left, right]) =>
284444 EPtr.box((left.loadValue() * right.loadValue()) >>> 0);
285445 });
286 
 446
287447 this._map.set(
288448 "native float operator*(float,float)",
289449 func => {
290450 func.implementation = ([left, right]) =>
291451 EPtr.box(Math.fround(left.loadValue() * right.loadValue()));
292452 });
293 
 453
294454 this._map.set(
295455 "native int operator/(int,int)",
296456 func => {
297457 func.implementation = ([left, right]) =>
298458 EPtr.box((left.loadValue() / right.loadValue()) | 0);
299459 });
300 
 460
301461 this._map.set(
302462 "native uint operator/(uint,uint)",
303463 func => {
304464 func.implementation = ([left, right]) =>
305465 EPtr.box((left.loadValue() / right.loadValue()) >>> 0);
306466 });
307 
 467
308468 this._map.set(
309469 "native int operator&(int,int)",
310470 func => {
311471 func.implementation = ([left, right]) =>
312472 EPtr.box(left.loadValue() & right.loadValue());
313473 });
314 
 474
315475 this._map.set(
316476 "native uint operator&(uint,uint)",
317477 func => {
318478 func.implementation = ([left, right]) =>
319479 EPtr.box((left.loadValue() & right.loadValue()) >>> 0);
320480 });
321 
 481
322482 this._map.set(
323483 "native int operator|(int,int)",
324484 func => {
325485 func.implementation = ([left, right]) =>
326486 EPtr.box(left.loadValue() | right.loadValue());
327487 });
328 
 488
329489 this._map.set(
330490 "native uint operator|(uint,uint)",
331491 func => {
332492 func.implementation = ([left, right]) =>
333493 EPtr.box((left.loadValue() | right.loadValue()) >>> 0);
334494 });
335 
 495
336496 this._map.set(
337497 "native int operator^(int,int)",
338498 func => {
339499 func.implementation = ([left, right]) =>
340500 EPtr.box(left.loadValue() ^ right.loadValue());
341501 });
342 
 502
343503 this._map.set(
344504 "native uint operator^(uint,uint)",
345505 func => {
346506 func.implementation = ([left, right]) =>
347507 EPtr.box((left.loadValue() ^ right.loadValue()) >>> 0);
348508 });
349 
 509
350510 this._map.set(
351511 "native int operator<<(int,uint)",
352512 func => {
353513 func.implementation = ([left, right]) =>
354514 EPtr.box(left.loadValue() << right.loadValue());
355515 });
356 
 516
357517 this._map.set(
358518 "native uint operator<<(uint,uint)",
359519 func => {
360520 func.implementation = ([left, right]) =>
361521 EPtr.box((left.loadValue() << right.loadValue()) >>> 0);
362522 });
363 
 523
364524 this._map.set(
365525 "native int operator>>(int,uint)",
366526 func => {
367527 func.implementation = ([left, right]) =>
368528 EPtr.box(left.loadValue() >> right.loadValue());
369529 });
370 
 530
371531 this._map.set(
372532 "native uint operator>>(uint,uint)",
373533 func => {
374534 func.implementation = ([left, right]) =>
375535 EPtr.box(left.loadValue() >>> right.loadValue());
376536 });
377 
 537
378538 this._map.set(
379539 "native int operator~(int)",
380540 func => {
381541 func.implementation = ([value]) => EPtr.box(~value.loadValue());
382542 });
383 
 543
384544 this._map.set(
385545 "native uint operator~(uint)",
386546 func => {
387547 func.implementation = ([value]) => EPtr.box((~value.loadValue()) >>> 0);
388548 });
389 
 549
390550 this._map.set(
391551 "native float operator/(float,float)",
392552 func => {
393553 func.implementation = ([left, right]) =>
394554 EPtr.box(Math.fround(left.loadValue() / right.loadValue()));
395555 });
396 
 556
397557 this._map.set(
398558 "native bool operator==(int,int)",
399559 func => {
400560 func.implementation = ([left, right]) =>
401561 EPtr.box(left.loadValue() == right.loadValue());
402562 });
403 
 563
404564 this._map.set(
405565 "native bool operator==(uint,uint)",
406566 func => {
407567 func.implementation = ([left, right]) =>
408568 EPtr.box(left.loadValue() == right.loadValue());
409569 });
410 
 570
411571 this._map.set(
412572 "native bool operator==(bool,bool)",
413573 func => {
414574 func.implementation = ([left, right]) =>
415575 EPtr.box(left.loadValue() == right.loadValue());
416576 });
417 
 577
418578 this._map.set(
419579 "native bool operator==(float,float)",
420580 func => {
421581 func.implementation = ([left, right]) =>
422582 EPtr.box(left.loadValue() == right.loadValue());
423583 });
424 
 584
425585 this._map.set(
426586 "native bool operator<(int,int)",
427587 func => {
428588 func.implementation = ([left, right]) =>
429589 EPtr.box(left.loadValue() < right.loadValue());
430590 });
431 
 591
432592 this._map.set(
433593 "native bool operator<(uint,uint)",
434594 func => {
435595 func.implementation = ([left, right]) =>
436596 EPtr.box(left.loadValue() < right.loadValue());
437597 });
438 
 598
439599 this._map.set(
440600 "native bool operator<(float,float)",
441601 func => {
442602 func.implementation = ([left, right]) =>
443603 EPtr.box(left.loadValue() < right.loadValue());
444604 });
445 
 605
446606 this._map.set(
447607 "native bool operator<=(int,int)",
448608 func => {
449609 func.implementation = ([left, right]) =>
450610 EPtr.box(left.loadValue() <= right.loadValue());
451611 });
452 
 612
453613 this._map.set(
454614 "native bool operator<=(uint,uint)",
455615 func => {
456616 func.implementation = ([left, right]) =>
457617 EPtr.box(left.loadValue() <= right.loadValue());
458618 });
459 
 619
460620 this._map.set(
461621 "native bool operator<=(float,float)",
462622 func => {
463623 func.implementation = ([left, right]) =>
464624 EPtr.box(left.loadValue() <= right.loadValue());
465625 });
466 
 626
467627 this._map.set(
468628 "native bool operator>(int,int)",
469629 func => {
470630 func.implementation = ([left, right]) =>
471631 EPtr.box(left.loadValue() > right.loadValue());
472632 });
473 
 633
474634 this._map.set(
475635 "native bool operator>(uint,uint)",
476636 func => {
477637 func.implementation = ([left, right]) =>
478638 EPtr.box(left.loadValue() > right.loadValue());
479639 });
480 
 640
481641 this._map.set(
482642 "native bool operator>(float,float)",
483643 func => {
484644 func.implementation = ([left, right]) =>
485645 EPtr.box(left.loadValue() > right.loadValue());
486646 });
487 
 647
488648 this._map.set(
489649 "native bool operator>=(int,int)",
490650 func => {
491651 func.implementation = ([left, right]) =>
492652 EPtr.box(left.loadValue() >= right.loadValue());
493653 });
494 
 654
495655 this._map.set(
496656 "native bool operator>=(uint,uint)",
497657 func => {
498658 func.implementation = ([left, right]) =>
499659 EPtr.box(left.loadValue() >= right.loadValue());
500660 });
501 
 661
502662 this._map.set(
503663 "native bool operator>=(float,float)",
504664 func => {

@@class Intrinsics {
538698 for (let setter of BuiltinVectorSetter.functions())
539699 this._map.set(setter.toString(), func => setter.instantiateImplementation(func));
540700 }
541 
 701
542702 add(thing)
543703 {
544704 let intrinsic = this._map.get(thing.toString());

Tools/WebGPUShadingLanguageRI/NameContext.js

@@class NameContext {
6969 return;
7070 }
7171
 72 if (thing.kind == Type) {
 73 this._set.add(thing);
 74 if (thing.name == "vector") {
 75 let array = this._map.get(thing.name);
 76 if (!array) {
 77 array = [];
 78 array.kind = Type;
 79 this._map.set(thing.name, array);
 80 }
 81 if (array.kind != Type)
 82 throw new WTypeError(thing.origin.originString, "Cannot reuse type name for function: " + thing.name);
 83 array.push(thing);
 84 return;
 85 } else {
 86 if (this._map.has(thing.name))
 87 throw new WTypeError(thing.origin.originString, "Duplicate name: " + thing.name);
 88 this._map.set(thing.name, thing);
 89 }
 90 return;
 91 }
 92
7293 if (this._map.has(thing.name))
7394 throw new WTypeError(thing.origin.originString, "Duplicate name: " + thing.name);
7495
7596 this._set.add(thing);
7697 this._map.set(thing.name, thing);
 98
7799 }
78100
79101 get(kind, name)

@@class NameContext {
102124 for (let func of thing)
103125 yield func;
104126 return;
 127 } else if (thing.kind === Type && (thing instanceof Array)) {
 128 for (let type of thing)
 129 yield type;
 130 return;
105131 }
106132 yield thing;
107133 }

@@class NameContext {
163189 {
164190 for (let value of this._map.values()) {
165191 if (value instanceof Array) {
166  for (let func of value)
167  yield func;
 192 for (let thing of value)
 193 yield thing;
168194 continue;
169195 }
170196 yield value;

Tools/WebGPUShadingLanguageRI/NameResolver.js

@@class NameResolver extends Visitor {
120120
121121 visitTypeRef(node)
122122 {
 123 super.visitTypeRef(node);
123124 let type = node.type;
124125 if (!type) {
125126 type = this._nameContext.get(Type, node.name);
126127 if (!type)
127128 throw new WTypeError(node.origin.originString, "Could not find type named " + node.name);
128  node.type = type;
 129 if (type instanceof Array)
 130 node.possibleOverloads = type;
 131 else
 132 node.type = type;
129133 }
130134 }
131135

@@class NameResolver extends Visitor {
208212
209213 super.visitCallExpression(node);
210214 }
211 
212  visitVectorType(node)
213  {
214  node.elementType.visit(this);
215  }
216215}

Tools/WebGPUShadingLanguageRI/NativeType.js

2525"use strict";
2626
2727class NativeType extends Type {
28  constructor(origin, name)
 28 constructor(origin, name, typeArguments)
2929 {
 30 if (!(typeArguments instanceof Array))
 31 throw new Error("type parameters not array: " + typeArguments);
3032 super();
3133 this._origin = origin;
3234 this._name = name;
 35 this._typeArguments = typeArguments;
3336 this._isNumber = false;
3437 this._isInt = false;
3538 this._isFloating = false;

@@class NativeType extends Type {
3841
3942 get origin() { return this._origin; }
4043 get name() { return this._name; }
 44 get typeArguments() { return this._typeArguments; }
4145 get isNative() { return true; }
4246
4347 // We let Intrinsics.js set these as it likes.

@@class NativeType extends Type {
5256
5357 toString()
5458 {
55  return `native typedef ${this.name}`;
 59 let result = `native typedef ${this.name}`;
 60 if (this.typeArguments.length)
 61 result += "<" + this.typeArguments.join(",") + ">";
 62 return result;
5663 }
5764
5865 static create(origin, name, typeArguments)
5966 {
60  // FIXME: For native types like Texture1D this should resolve the type to something concrete by changing the type name.
61  if (typeArguments.length)
62  throw new WTypeError(origin.originString, `${name}<${typeArguments.join(",")}>: Support for native types with type arguments is currently unimplemented.`);
 67 if (name == "vector")
 68 return new VectorType(origin, name, typeArguments);
6369
64  if (allVectorTypeNames().indexOf(name) > -1)
65  return new VectorType(origin, name);
66 
67  return new NativeType(origin, name);
 70 return new NativeType(origin, name, typeArguments);
6871 }
6972}
7073

Tools/WebGPUShadingLanguageRI/Prepare.js

@@let prepare = (() => {
4040 }
4141
4242 foldConstexprs(program);
43  removeTypeArguments(program);
4443
4544 let nameResolver = createNameResolver(program);
4645 resolveNamesInTypes(program, nameResolver);

@@let prepare = (() => {
5453 synthesizeDefaultConstructorOperator(program);
5554 resolveNamesInFunctions(program, nameResolver);
5655 resolveTypeDefsInFunctions(program);
 56 checkTypesWithArguments(program);
5757
5858 check(program);
5959 checkLiteralTypes(program);

@@let prepare = (() => {
6666 checkLoops(program);
6767 checkRecursion(program);
6868 checkProgramWrapped(program);
 69 checkTypesWithArguments(program);
6970 findHighZombies(program);
7071 program.visit(new StructLayoutBuilder());
7172 inline(program);

Tools/WebGPUShadingLanguageRI/Program.js

@@class Program extends Node {
4848 if (statement instanceof Func) {
4949 let array = this._functions.get(statement.name);
5050 if (!array)
51  this._functions.set(statement.name, array = []);
 51 this.functions.set(statement.name, array = []);
5252 array.push(statement);
53  } else if (statement instanceof Type)
54  this._types.set(statement.name, statement);
55  else
 53 } else if (statement instanceof Type) {
 54 if (statement.isNative && statement.name == "vector") {
 55 let array = this.types.get(statement.name);
 56 if (!array)
 57 this.types.set(statement.name, array = []);
 58 array.push(statement);
 59 } else
 60 this.types.set(statement.name, statement);
 61 } else
5662 throw new Error("Statement is not a function or type: " + statement);
57  this._topLevelStatements.push(statement);
58  this._globalNameContext.add(statement);
 63 this.topLevelStatements.push(statement);
 64 this.globalNameContext.add(statement);
5965 }
6066
6167 toString()
6268 {
63  if (!this._topLevelStatements.length)
 69 if (!this.topLevelStatements.length)
6470 return "";
6571 return this._topLevelStatements.join(";") + ";";
6672 }

Tools/WebGPUShadingLanguageRI/RecursiveTypeChecker.js

@@class RecursiveTypeChecker extends Visitor {
5151 visitTypeRef(node)
5252 {
5353 super.visitTypeRef(node);
54  node.type.visit(this);
 54 if (node.possibleOverloads) {
 55 for (let overload of node.possibleOverloads)
 56 overload.visit(this);
 57 } else
 58 node.type.visit(this);
5559 }
5660}
5761

Tools/WebGPUShadingLanguageRI/RemoveTypeArguments.js

1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 "use strict";
26 
27 function removeTypeArguments(program)
28 {
29  class RemoveTypeArguments extends Visitor {
30  static resolveNameAndArguments(node)
31  {
32  if (!node.typeArguments)
33  return node.name;
34 
35  switch (node.name) {
36  case "vector":
37  if (node.typeArguments.length != 2)
38  throw new WSyntaxError(node.originString, `${node.name} should have 2 type arguments, got ${node.typeArguments.length}.`);
39 
40  const elementTypeName = node.typeArguments[0].name;
41  const lengthValue = node.typeArguments[1].value;
42 
43  if (VectorElementTypes.indexOf(elementTypeName) < 0)
44  throw new WSyntaxError(node.originString, `${elementTypeName} is not a valid vector element type.`);
45  if (VectorElementSizes.indexOf(lengthValue) < 0)
46  throw new WSyntaxError(node.originString, `${lengthValue} is not a valid size for vectors with element type ${elementTypeName}.`);
47 
48  return `${elementTypeName}${lengthValue}`;
49  // FIXME: Further cases for matrices, textures, etc.
50  default:
51  if (node.typeArguments.length)
52  throw new WSyntaxError(`${node.name}${arguments.join(", ")} is not a permitted generic type or function`);
53  return node.name;
54  }
55  }
56 
57  visitTypeRef(node)
58  {
59  node._name = RemoveTypeArguments.resolveNameAndArguments(node);
60  node._typeArguments = null;
61  }
62  }
63 
64  program.visit(new RemoveTypeArguments());
65 }

Tools/WebGPUShadingLanguageRI/ResolveNames.js

@@function createNameResolver(program)
3131
3232function resolveNamesInTypes(program, nameResolver)
3333{
34  for (let type of program.types.values())
35  nameResolver.doStatement(type);
 34 for (let type of program.types.values()) {
 35 if (type instanceof Array) {
 36 for (let constituentType of type)
 37 nameResolver.doStatement(constituentType);
 38 } else
 39 nameResolver.doStatement(type);
 40 }
3641}
3742
3843function resolveNamesInFunctions(program, nameResolver)

Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js

@@function resolveOverloadImpl(functions, argumentTypes, returnType, allowEntryPoi
100100
101101 return {failures: ambiguityList.map(overload => new OverloadResolutionFailure(overload.func, message))};
102102}
 103
 104function resolveTypeOverloadImpl(types, typeArguments)
 105{
 106 if (!types)
 107 throw new Error("Null types; that should have been caught by the caller.");
 108
 109 let failures = [];
 110 let successes = [];
 111 for (let type of types) {
 112 let overload = inferTypesForTypeArguments(type, typeArguments);
 113 if (overload.failure)
 114 failures.push(overload.failure);
 115 else
 116 successes.push(overload);
 117 }
 118
 119 if (!successes.length)
 120 return {failures: failures};
 121
 122 if (successes.length == 1)
 123 return successes[0];
 124
 125 let message = "Ambiguous overload - types mutually applicable";
 126 return {failures: successes.map(overload => new TypeOverloadResolutionFailure(overload.type, message))};
 127}

Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js

2727function resolveTypeDefsInTypes(program)
2828{
2929 let resolver = new TypeDefResolver();
30  for (let type of program.types.values())
31  type.visit(resolver);
 30 for (let type of program.types.values()) {
 31 if (type instanceof Array) {
 32 for (let constituentType of type)
 33 constituentType.visit(resolver);
 34 } else
 35 type.visit(resolver);
 36 }
3237}
3338
3439function resolveTypeDefsInFunctions(program)

Tools/WebGPUShadingLanguageRI/Rewriter.js

@@class Rewriter {
9797
9898 visitTypeRef(node)
9999 {
100  let result = new TypeRef(node.origin, node.name);
 100 let result = new TypeRef(node.origin, node.name, node.typeArguments.map(argument => argument.visit(this)));
 101 if (node.possibleOverloads)
 102 result.possibleOverloads = node.possibleOverloads.map(overload => Node.visit(overload, this));
101103 if (node.type)
102104 result.type = Node.visit(node.type, this);
103105 return result;

@@class Rewriter {
382384
383385 visitVectorType(node)
384386 {
385  const vecType = new VectorType(node.origin, node.name);
 387 const vecType = new VectorType(node.origin, node.name, node.typeArguments.map(argument => argument.visit(this)));
386388 vecType._elementType = node.elementType.visit(this);
387389 return vecType;
388390 }

Tools/WebGPUShadingLanguageRI/SPIRV.html

@@td {
4343 <script src="CheckRecursion.js"></script>
4444 <script src="CheckRecursiveTypes.js"></script>
4545 <script src="CheckReturns.js"></script>
 46 <script src="CheckTypesWithArguments.js"></script>
4647 <script src="CheckUnreachableCode.js"></script>
4748 <script src="CheckWrapped.js"></script>
4849 <script src="Checker.js"></script>

@@td {
116117 <script src="ReadModifyWriteExpression.js"></script>
117118 <script src="RecursionChecker.js"></script>
118119 <script src="RecursiveTypeChecker.js"></script>
119  <script src="RemoveTypeArguments.js"></script>
120120 <script src="ResolveNames.js"></script>
121121 <script src="ResolveOverloadImpl.js"></script>
122122 <script src="ResolveProperties.js"></script>

@@td {
140140 <script src="TypeDef.js"></script>
141141 <script src="TypeDefResolver.js"></script>
142142 <script src="TypeRef.js"></script>
 143 <script src="TypeOverloadResolutionFailure.js"></script>
143144 <script src="TypedValue.js"></script>
144145 <script src="UintLiteral.js"></script>
145146 <script src="UintLiteralType.js"></script>

Tools/WebGPUShadingLanguageRI/StandardLibrary.js

@@let standardLibrary = `
3333native typedef void;
3434native typedef bool;
3535native typedef uchar;
 36native typedef ushort;
3637native typedef uint;
 38native typedef char;
 39native typedef short;
3740native typedef int;
 41native typedef half;
3842native typedef float;
39 
40 // FIXME: Add support for these types to Intrinsics.js
41 // native typedef ushort;
42 // native typedef char;
43 // native typedef short;
44 // native typedef half;
45 // native typedef atomic_int;
46 // native typedef atomic_uint;
 43native typedef atomic_int;
 44native typedef atomic_uint;
 45
 46native typedef vector<bool, 2>;
 47typedef bool2 = vector<bool, 2>;
 48native typedef vector<bool, 3>;
 49typedef bool3 = vector<bool, 3>;
 50native typedef vector<bool, 4>;
 51typedef bool4 = vector<bool, 4>;
 52native typedef vector<uchar, 2>;
 53typedef uchar2 = vector<uchar, 2>;
 54native typedef vector<uchar, 3>;
 55typedef uchar3 = vector<uchar, 3>;
 56native typedef vector<uchar, 4>;
 57typedef uchar4 = vector<uchar, 4>;
 58native typedef vector<ushort, 2>;
 59typedef ushort2 = vector<ushort, 2>;
 60native typedef vector<ushort, 3>;
 61typedef ushort3 = vector<ushort, 3>;
 62native typedef vector<ushort, 4>;
 63typedef ushort4 = vector<ushort, 4>;
 64native typedef vector<uint, 2>;
 65typedef uint2 = vector<uint, 2>;
 66native typedef vector<uint, 3>;
 67typedef uint3 = vector<uint, 3>;
 68native typedef vector<uint, 4>;
 69typedef uint4 = vector<uint, 4>;
 70native typedef vector<char, 2>;
 71typedef char2 = vector<char, 2>;
 72native typedef vector<char, 3>;
 73typedef char3 = vector<char, 3>;
 74native typedef vector<char, 4>;
 75typedef char4 = vector<char, 4>;
 76native typedef vector<short, 2>;
 77typedef short2 = vector<short, 2>;
 78native typedef vector<short, 3>;
 79typedef short3 = vector<short, 3>;
 80native typedef vector<short, 4>;
 81typedef short4 = vector<short, 4>;
 82native typedef vector<int, 2>;
 83typedef int2 = vector<int, 2>;
 84native typedef vector<int, 3>;
 85typedef int3 = vector<int, 3>;
 86native typedef vector<int, 4>;
 87typedef int4 = vector<int, 4>;
 88native typedef vector<half, 2>;
 89typedef half2 = vector<half, 2>;
 90native typedef vector<half, 3>;
 91typedef half3 = vector<half, 3>;
 92native typedef vector<half, 4>;
 93typedef half4 = vector<half, 4>;
 94native typedef vector<float, 2>;
 95typedef float2 = vector<float, 2>;
 96native typedef vector<float, 3>;
 97typedef float3 = vector<float, 3>;
 98native typedef vector<float, 4>;
 99typedef float4 = vector<float, 4>;
47100
48101native operator int(uint);
49102native operator int(uchar);

@@bool operator~(bool value)
147200{
148201 return !value;
149202}
150 
151 native typedef uchar2;
152 native typedef uchar3;
153 native typedef uchar4;
154 
155 native typedef uint2;
156 native typedef uint3;
157 native typedef uint4;
158 
159 native typedef int2;
160 native typedef int3;
161 native typedef int4;
162 
163 native typedef float2;
164 native typedef float3;
165 native typedef float4;
166203`;
167204
168205// FIXME: Once the standard library has been replaced with a new version, this comments should be removed.
169206// This list is used to restrict the availability of vector types available in the langauge.
170207// Permissible vector element types must appear in this list and in the standard library
171 const VectorElementTypes = [ /*"bool",*/ "uchar", /*"char", "ushort", "short",*/ "uint", "int", /* "half", */"float" ];
 208const VectorElementTypes = [ "bool", "uchar", "char", "ushort", "short", "uint", "int", "half", "float" ];
172209const VectorElementSizes = [ 2, 3, 4 ];
173210
174211function allVectorTypeNames()

Tools/WebGPUShadingLanguageRI/StatementCloner.js

@@class StatementCloner extends Rewriter {
5050
5151 visitNativeType(node)
5252 {
53  return new NativeType(node.origin, node.name);
 53 return new NativeType(node.origin, node.name, node.typeArguments.map(argument => argument.visit(this)));
5454 }
5555
5656 visitTypeDef(node)

Tools/WebGPUShadingLanguageRI/SynthesizeDefaultConstructorOperator.js

@@function synthesizeDefaultConstructorOperator(program)
4545 types.add(node);
4646 super.visitElementalType(node);
4747 }
 48
 49 visitVectorType(node)
 50 {
 51 types.add(node);
 52 super.visitVectorType(node);
 53 }
4854 }
4955
5056 program.visit(new FindAllTypes());

Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js

@@function synthesizeStructAccessors(program)
5151
5252 function createTypeRef()
5353 {
54  return TypeRef.instantiate(type);
 54 return TypeRef.wrap(type);
5555 }
5656
5757 let isCast = false;

Tools/WebGPUShadingLanguageRI/Test.html

3737<script src="CheckRecursion.js"></script>
3838<script src="CheckRecursiveTypes.js"></script>
3939<script src="CheckReturns.js"></script>
 40<script src="CheckTypesWithArguments.js"></script>
4041<script src="CheckUnreachableCode.js"></script>
4142<script src="CheckWrapped.js"></script>
4243<script src="Checker.js"></script>

110111<script src="ReadModifyWriteExpression.js"></script>
111112<script src="RecursionChecker.js"></script>
112113<script src="RecursiveTypeChecker.js"></script>
113 <script src="RemoveTypeArguments.js"></script>
114114<script src="ResolveNames.js"></script>
115115<script src="ResolveOverloadImpl.js"></script>
116116<script src="ResolveProperties.js"></script>

134134<script src="TypeDef.js"></script>
135135<script src="TypeDefResolver.js"></script>
136136<script src="TypeRef.js"></script>
 137<script src="TypeOverloadResolutionFailure.js"></script>
137138<script src="TypedValue.js"></script>
138139<script src="UintLiteral.js"></script>
139140<script src="UintLiteralType.js"></script>

Tools/WebGPUShadingLanguageRI/Test.js

@@tests.shaderTypes = function()
28812881 }
28822882 fragment Boo bar(Foo stageIn)
28832883 {
2884  return boo();
 2884 return Boo();
28852885 }
28862886 `),
28872887 (e) => e instanceof WTypeError);

@@tests.shaderTypes = function()
29042904
29052905tests.vectorTypeSyntax = function()
29062906{
2907  const program = doPrep(`
 2907 let program = doPrep(`
29082908 int foo2()
29092909 {
29102910 int2 x;

@@tests.vectorTypeSyntax = function()
29392939 checkInt(program, callFunction(program, "foo2", []), 4);
29402940 checkInt(program, callFunction(program, "foo3", []), 5);
29412941 checkInt(program, callFunction(program, "foo4", []), 6);
 2942 checkBool(program, callFunction(program, "vec2OperatorCast", []), true);
 2943
 2944 program = doPrep(`
 2945 typedef i = int;
 2946 int foo2()
 2947 {
 2948 int2 x;
 2949 vector<i, 2> z = int2(3, 4);
 2950 x = z;
 2951 return x.y;
 2952 }
 2953
 2954 bool vec2OperatorCast()
 2955 {
 2956 int2 x = vector<i,2>(1, 2);
 2957 vector<i, 2> y = int2(1, 2);
 2958 return x == y && x.x == 1 && x.y == 2 && y.x == 1 && y.y == 2;
 2959 }`);
29422960
 2961 checkInt(program, callFunction(program, "foo2", []), 4);
29432962 checkBool(program, callFunction(program, "vec2OperatorCast", []), true);
29442963}
29452964

Tools/WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js

 1/*
 2 * Copyright (C) 2018 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25"use strict";
 26
 27class TypeOverloadResolutionFailure {
 28 constructor(type, reason)
 29 {
 30 this._type = type;
 31 this._reason = reason;
 32 }
 33
 34 get type() { return this._type; }
 35 get reason() { return this._reason; }
 36
 37 toString()
 38 {
 39 return this.type.toString() + " did not match because: " + this.reason;
 40 }
 41}
 42

Tools/WebGPUShadingLanguageRI/TypeRef.js

2525"use strict";
2626
2727class TypeRef extends Type {
28  constructor(origin, name, typeArguments = null)
 28 constructor(origin, name, typeArguments = [])
2929 {
3030 super();
3131 this._origin = origin;
3232 this._name = name;
3333 this._type = null;
 34 this._possibleOverloads = null;
3435 this._typeArguments = typeArguments;
3536 }
3637

@@class TypeRef extends Type {
3839 {
3940 if (type instanceof TypeRef)
4041 return type;
41  let result = new TypeRef(type.origin, type.name);
42  result.type = type;
43  return result;
44  }
45 
46  static instantiate(type)
47  {
48  let result = new TypeRef(type.origin, type.name);
 42 let result;
 43 if (type instanceof NativeType)
 44 result = new TypeRef(type.origin, type.name, type.typeArguments);
 45 else
 46 result = new TypeRef(type.orgin, type.name);
4947 result.type = type;
5048 return result;
5149 }

@@class TypeRef extends Type {
6361 {
6462 this._type = newType;
6563 }
 64
 65 get possibleOverloads()
 66 {
 67 return this._possibleOverloads;
 68 }
 69
 70 set possibleOverloads(newOverloads)
 71 {
 72 if (this.type)
 73 throw new Error("TypeRefs with known type should not have overloads.");
 74 this._possibleOverloads = newOverloads;
 75 }
 76
 77 resolve(possibleOverloads, program)
 78 {
 79 if (!possibleOverloads)
 80 throw new WTypeError(this.origin.originString, "Did not find any types named " + this.name);
 81
 82 let failures = [];
 83 let overload = resolveTypeOverloadImpl(possibleOverloads, this.typeArguments);
 84
 85 if (!overload.type) {
 86 failures.push(...overload.failures);
 87 let message = "Did not find type named " + this.name + " for type arguments ";
 88 message += "(" + this.typeArguments + ")";
 89 if (failures.length)
 90 message += ", but considered:\n" + failures.join("\n")
 91 throw new WTypeError(this.origin.originString, message);
 92 }
 93
 94 for (let i = 0; i < this.typeArguments.length; ++i) {
 95 let typeArgument = this.typeArguments[i];
 96 let resolvedTypeArgument = overload.type.typeArguments[i];
 97 let result = typeArgument.equalsWithCommit(resolvedTypeArgument);
 98 if (!result)
 99 throw new Error("At " + this.origin.originString + " argument types for Type and TypeRef not equal: argument type = " + typeArgument + ", resolved type argument = " + resolvedTypeArgument);
 100 if (resolvedTypeArgument.constructor.name == "GenericLiteral") {
 101 result = typeArgument.type.equalsWithCommit(resolvedTypeArgument.type);
 102 if (!result)
 103 throw new Error("At " + this.origin.originString + " argument types for Type and TypeRef not equal: argument type = " + typeArgument + ", resolved type argument = " + resolvedTypeArgument);
 104 }
 105
 106 }
 107 this.type = overload.type;
 108 }
66109
67110 get unifyNode()
68111 {

@@class TypeRef extends Type {
99142 {
100143 if (!this.name)
101144 return this.type.toString();
102  return this.name;
 145 let result = this.name;
 146 if (this.typeArguments.length > 0)
 147 result += "<" + this.typeArguments.map(argument => argument.toString()).join(",") + ">";
 148 return result;
103149 }
104150}
105151

Tools/WebGPUShadingLanguageRI/UnificationContext.js

@@class UnificationContext {
9292
9393 verify()
9494 {
 95 // We do a two-phase pre-verification. This gives literals a chance to select a more specific type.
 96 let preparations = [];
 97 for (let node of this.nodes) {
 98 let preparation = node.prepareToVerify(this);
 99 if (preparation)
 100 preparations.push(preparation);
 101 }
 102 for (let preparation of preparations) {
 103 let result = preparation();
 104 if (!result.result)
 105 return result;
 106 }
 107
95108 for (let typeArgument of this.typeArguments()) {
96109 let result = typeArgument.verifyAsArgument(this);
97110 if (!result.result)

Tools/WebGPUShadingLanguageRI/VectorType.js

2525"use strict";
2626
2727class VectorType extends NativeType {
28  constructor(origin, name)
 28 constructor(origin, name, typeArguments)
2929 {
30  super(origin, name);
31  const match = /^([A-z]+)([0-9])$/.exec(name);
32  if (!match)
33  throw new WTypeError(origin.originString, `${name} doesn't match the format for vector type names.'`);
34 
35  this._elementType = new TypeRef(origin, match[1]);
36  this._numElementsValue = parseInt(match[2]);
 30 super(origin, name, typeArguments);
3731 }
3832
39  get elementType() { return this._elementType; }
40  get numElementsValue() { return this._numElementsValue; }
 33 get elementType() { return this.typeArguments[0]; }
 34 get numElements() { return this.typeArguments[1]; }
 35 get numElementsValue() { return this.numElements.value; }
4136 get size() { return this.elementType.size * this.numElementsValue; }
4237
4338 unifyImpl(unificationContext, other)

@@class VectorType extends NativeType {
5954
6055 toString()
6156 {
62  return `native typedef ${this.elementType}${this.numElementsValue}`;
 57 return `native typedef vector<${this.elementType}, ${this.numElementsValue}>`;
6358 }
6459}
6560

Tools/WebGPUShadingLanguageRI/Visitor.js

@@class Visitor {
6868
6969 visitTypeRef(node)
7070 {
 71 for (let typeArgument of node.typeArguments)
 72 typeArgument.visit(this);
7173 }
7274
7375 visitNativeType(node)
7476 {
 77 for (let typeArgument of node.typeArguments)
 78 typeArgument.visit(this);
7579 }
7680
7781 visitTypeDef(node)

@@class Visitor {
327331 visitVectorType(node)
328332 {
329333 node.elementType.visit(this);
 334 node.numElements.visit(this);
330335 }
331336}
332337

Tools/WebGPUShadingLanguageRI/index.html

3838<script src="CheckRecursiveTypes.js"></script>
3939<script src="CheckReturns.js"></script>
4040<script src="CheckUnreachableCode.js"></script>
 41<script src="CheckTypesWithArguments.js"></script>
4142<script src="CheckWrapped.js"></script>
4243<script src="Checker.js"></script>
4344<script src="CloneProgram.js"></script>

110111<script src="ReadModifyWriteExpression.js"></script>
111112<script src="RecursionChecker.js"></script>
112113<script src="RecursiveTypeChecker.js"></script>
113 <script src="RemoveTypeArguments.js"></script>
114114<script src="ResolveNames.js"></script>
115115<script src="ResolveOverloadImpl.js"></script>
116116<script src="ResolveProperties.js"></script>

134134<script src="TypeDef.js"></script>
135135<script src="TypeDefResolver.js"></script>
136136<script src="TypeRef.js"></script>
 137<script src="TypeOverloadResolutionFailure.js"></script>
137138<script src="TypedValue.js"></script>
138139<script src="UintLiteral.js"></script>
139140<script src="UintLiteralType.js"></script>