Diff
Modified: trunk/Tools/ChangeLog (235236 => 235237)
--- trunk/Tools/ChangeLog 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/ChangeLog 2018-08-23 19:52:16 UTC (rev 235237)
@@ -1,3 +1,134 @@
+2018-08-23 Myles C. Maxfield <[email protected]>
+
+ [WHLSL] Allow native types to have type arguments (like "vector<float, 4>")
+ https://bugs.webkit.org/show_bug.cgi?id=188773
+
+ Reviewed by Filip Pizlo.
+
+ Before this patch, it was impossible to represent "native typedef vector<float, 4>" because NativeTypes couldn't have
+ typeArguments.
+
+ Previously, the way to identify a type was strictly by name, which was represented by a string. Therefore, when something like
+ "vector<int, 3>" was parsed, it would produce a TypeRef with the name "vector" and typeArguments [TypeRef, IntLiteral]. Then,
+ there was a pass to convert the TypeRef to have the name "int3" and no typeArguments. After this transformation, each type could
+ be uniquely identified by name. That name was then matched to the string-only NativeType name.
+
+ This is okay for vectors and matrices, but it is unfortunate for textures (e.g. Texture2D<float4>) because they don't have any
+ natural string-only name. In addition, the canonicalization would have to be made aware of the fact that Texture2D<float4> is
+ the same as Texture2D<vector<float, 4>>. Similarly, an author may wish to typedef float4 to a different name.
+
+ It would be possible to mangle the names of the texture types to something unique, but then we lose information about the inner
+ type. For example, if we did this, Visitor wouldn't recurse into the float4 when encountering Texture2D<float4> because that
+ information would be lost. This could potentially make operations like programWithUnnecessaryThingsRemoved() more difficult to
+ implement in the future.
+
+ So, it would be better to have each type uniquely identified by (name, typeArguments). TypeRef will therefore also have
+ typeArguments which are used to determine which type it is referencing. After this analysis is done to determine what each
+ TypeRef is referencing, subsequent passes shouldn't care about the typeArguments and should only care about the .type field
+ which had been set - this was true even before this patch.
+
+ This means that NameContext has to aggregate types that accept typeArguments into arrays, where each array holds all the Types
+ that have the same name but different typeArguments. Then, when we need to match a TypeRef with a Type, we can ask the
+ NameContext for the appropriate array. This is the same way that function resolution works.
+
+ We can use Node.unify() to determine whether a TypeRef matches a NativeType. Eventually, this will go away, but for now, this is
+ an okay start. This works just about the same way that function overload resolution works.
+
+ * WebGPUShadingLanguageRI/All.js:
+ * WebGPUShadingLanguageRI/CallExpression.js:
+ (CallExpression.prototype.resolve):
+ * WebGPUShadingLanguageRI/CheckTypesWithArguments.js: Copied from Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js. After types
+ have been resolved, there should be no TypeRefs with name "vector" that don't have type arguments. This is just a sanity check.
+ (checkTypesWithArguments.TypeWithArgumentsChecker.prototype.visitTypeRef):
+ (checkTypesWithArguments.TypeWithArgumentsChecker):
+ (checkTypesWithArguments):
+ * WebGPUShadingLanguageRI/Checker.js:
+ (Checker.prototype.visitProgram): Program.types mirrors NameContext: it's a Map that maps strings to types. Because types with
+ typeArguments share names, this has to be updated to map strings to arrays for these types.
+ (Checker.prototype.visitTypeRef):
+ * WebGPUShadingLanguageRI/InferTypesForCall.js:
+ (inferTypesForCall): Don't know why this was here.
+ (inferTypesForTypeArguments): Same as inferTypesForCall, but this one is for matching type arguments.
+ * WebGPUShadingLanguageRI/Intrinsics.js: Adding the types. This patch also adds some scalar types like half, char, etc, but they
+ don't have any functions which accept them. Those will be tested in my next patch which adds math functions for these types. This
+ moves in the direction of matching the standard library in the spec.
+ (Intrinsics.cast):
+ (Intrinsics.bitwiseCast):
+ (Intrinsics.castToHalf):
+ (Intrinsics.):
+ (Intrinsics):
+ * WebGPUShadingLanguageRI/NameContext.js: Aggregate types with typeArguments into arrays.
+ (NameContext.prototype.add):
+ (NameContext.prototype.get let):
+ (NameContext.underlyingThings.prototype.else):
+ (NameContext.prototype.Symbol.iterator):
+ (NameContext):
+ * WebGPUShadingLanguageRI/NameResolver.js:
+ (NameResolver.prototype.visitTypeRef): Call TypeRef.resolve().
+ (NameResolver.prototype.visitCallExpression):
+ (NameResolver):
+ (NameResolver.prototype.visitVectorType): Deleted.
+ * WebGPUShadingLanguageRI/NativeType.js: NativeTypes can have type arguments now.
+ (NativeType):
+ (NativeType.prototype.get typeArguments):
+ (NativeType.prototype.toString):
+ (NativeType.create):
+ * WebGPUShadingLanguageRI/Prepare.js:
+ (let.prepare):
+ * WebGPUShadingLanguageRI/Program.js: Update to work with types aggregated into arrays.
+ (Program.prototype.add):
+ (Program.prototype.toString):
+ (Program):
+ * WebGPUShadingLanguageRI/RemoveTypeArguments.js: Removed.
+ * WebGPUShadingLanguageRI/ResolveNames.js: Update to work with types aggregated into arrays.
+ (resolveNamesInTypes):
+ * WebGPUShadingLanguageRI/ResolveOverloadImpl.js: Resolve the type overload for types with typeArguments.
+ * WebGPUShadingLanguageRI/ResolveTypeDefs.js: Update to work with types aggregated into arrays.
+ (resolveTypeDefsInTypes):
+ * WebGPUShadingLanguageRI/Rewriter.js: TypeRefs and Native/Vector types can have typeArguments.
+ (Rewriter.prototype.visitTypeRef):
+ (Rewriter.prototype.visitVectorType):
+ (Rewriter):
+ * WebGPUShadingLanguageRI/SPIRV.html:
+ * WebGPUShadingLanguageRI/StandardLibrary.js: Matches Intrinsics.
+ (bool.operator):
+ * WebGPUShadingLanguageRI/StatementCloner.js: Native types can have typeArguments.
+ (StatementCloner.prototype.visitNativeType):
+ * WebGPUShadingLanguageRI/SynthesizeDefaultConstructorOperator.js: Vector types need constructors too.
+ (synthesizeDefaultConstructorOperator.FindAllTypes.prototype.visitVectorType):
+ (synthesizeDefaultConstructorOperator.FindAllTypes):
+ (synthesizeDefaultConstructorOperator):
+ * WebGPUShadingLanguageRI/SynthesizeStructAccessors.js: No reason to distinguish between wrapping and instantiating a TypeRef.
+ (synthesizeStructAccessors.createTypeRef):
+ * WebGPUShadingLanguageRI/Test.html:
+ * WebGPUShadingLanguageRI/Test.js:
+ * WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js: Copied from Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js.
+ (TypeOverloadResolutionFailure):
+ (TypeOverloadResolutionFailure.prototype.get type):
+ (TypeOverloadResolutionFailure.prototype.get reason):
+ (TypeOverloadResolutionFailure.prototype.toString):
+ * WebGPUShadingLanguageRI/TypeRef.js:
+ (TypeRef.wrap):
+ (TypeRef.prototype.resolve): Figure out which item in the possibleOverloads array matches this.
+ (TypeRef.prototype.toString):
+ (TypeRef):
+ (TypeRef.instantiate): Deleted.
+ * WebGPUShadingLanguageRI/UnificationContext.js: We need to give literals a chance to assume their preferred type. This
+ adds this facility back into the compiler (it was previously deleted).
+ (UnificationContext.prototype.verify):
+ * WebGPUShadingLanguageRI/VectorType.js: Vector types have type arguments.
+ (VectorType):
+ (VectorType.prototype.get elementType):
+ (VectorType.prototype.get numElements):
+ (VectorType.prototype.get numElementsValue):
+ (VectorType.prototype.toString):
+ * WebGPUShadingLanguageRI/Visitor.js: Iterate over the typeArguments.
+ (Visitor.prototype.visitTypeRef):
+ (Visitor.prototype.visitNativeType):
+ (Visitor.prototype.visitVectorType):
+ (Visitor):
+ * WebGPUShadingLanguageRI/index.html:
+
2018-08-23 Wenson Hsieh <[email protected]>
[Attachment Support] Attachment elements don't appear in drag images on macOS
Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/All.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -60,6 +60,7 @@
load("CheckRecursion.js");
load("CheckRecursiveTypes.js");
load("CheckReturns.js");
+load("CheckTypesWithArguments.js");
load("CheckUnreachableCode.js");
load("CheckWrapped.js");
load("Checker.js");
@@ -133,7 +134,6 @@
load("ReadModifyWriteExpression.js");
load("RecursionChecker.js");
load("RecursiveTypeChecker.js");
-load("RemoveTypeArguments.js");
load("ResolveNames.js");
load("ResolveOverloadImpl.js");
load("ResolveProperties.js");
@@ -157,6 +157,7 @@
load("TypeDef.js");
load("TypeDefResolver.js");
load("TypeRef.js");
+load("TypeOverloadResolutionFailure.js");
load("TypedValue.js");
load("UintLiteral.js");
load("UintLiteralType.js");
@@ -170,4 +171,4 @@
load("WTrapError.js");
load("WTypeError.js");
load("WhileLoop.js");
-load("WrapChecker.js");
\ No newline at end of file
+load("WrapChecker.js");
Modified: trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -64,7 +64,6 @@
overload.func = func;
}
-
if (!overload.func) {
failures.push(...overload.failures);
let message = "Did not find function named " + this.name + " for call with ";
Copied: trunk/Tools/WebGPUShadingLanguageRI/CheckTypesWithArguments.js (from rev 235236, trunk/Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js) (0 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/CheckTypesWithArguments.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/CheckTypesWithArguments.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+"use strict";
+
+function checkTypesWithArguments(program)
+{
+ class TypeWithArgumentsChecker extends Visitor {
+ visitTypeRef(node)
+ {
+ if (node.name == "vector" && node.typeArguments.length == 0)
+ throw new Error("Builtin type ${node.name} should always have type arguments.");
+ }
+ }
+ program.visit(new TypeWithArgumentsChecker());
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/Checker.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -41,8 +41,13 @@
statement.visit(this);
}
- for (let type of node.types.values())
- doStatement(type);
+ for (let type of node.types.values()) {
+ if (type instanceof Array) {
+ for (let constituentType of type)
+ doStatement(constituentType);
+ } else
+ doStatement(type);
+ }
for (let funcs of node.functions.values()) {
for (let func of funcs) {
this.visitFunc(func);
@@ -247,6 +252,10 @@
{
if (!node.type)
throw new Error("Type reference without a type in checker: " + node + " at " + node.origin);
+ // All the structs will be visited by visitProgram() iterating through each top-level type.
+ // We don't want to recurse here because the contents of structs can refer to themselves (e.g. a linked list),
+ // and this would can an infinite loop.
+ // Typedefs can't refer to themselves because we check that in TypeDefResolver.
if (!(node.type instanceof StructType))
node.type.visit(this);
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/InferTypesForCall.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/InferTypesForCall.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/InferTypesForCall.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -36,12 +36,8 @@
if (!argumentTypes[i].unify(unificationContext, func.parameters[i].type))
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 + ")")};
}
- if (returnType && !returnType.unify(unificationContext, func.returnType)) {
- if (func.returnType.toString() == "vector") {
- returnType.unify(unificationContext, func.returnType)
- }
+ if (returnType && !returnType.unify(unificationContext, func.returnType))
return {failure: new OverloadResolutionFailure(func, "Return type " + func.returnType + " does not match " + returnType)};
- }
let verificationResult = unificationContext.verify();
if (!verificationResult.result)
return {failure: new OverloadResolutionFailure(func, verificationResult.reason)};
@@ -49,3 +45,21 @@
return {func, unificationContext};
}
+function inferTypesForTypeArguments(type, typeArguments)
+{
+ if (typeArguments.length != type.typeArguments.length)
+ return {failure: new TypeOverloadResolutionFailure(type, "Wrong number of arguments (passed " + typeArguments.length + ", require " + type.typeArguments.length + ")")};
+ let unificationContext = new UnificationContext();
+
+ for (let i = 0; i < typeArguments.length; ++i) {
+ if (!typeArguments[i])
+ throw new Error("Null type argument at i = " + i);
+ if (!typeArguments[i].unify(unificationContext, type.typeArguments[i]))
+ 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 + ")")};
+ }
+ let verificationResult = unificationContext.verify();
+ if (!verificationResult.result)
+ return {failure: new TypeOverloadResolutionFailure(type, verificationResult.reason)};
+
+ return {type, unificationContext};
+}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -33,15 +33,7 @@
// to catch the intrinsics must be based on the type names that StandardLibrary.js uses.
// For example, if a native function is declared using "int" rather than "int", then we must
// use "int" here, since we don't yet know that they are the same type.
-
- this._map.set(
- "native typedef void",
- type => {
- this.void = type;
- type.size = 0;
- type.populateDefaultValue = () => { };
- });
-
+
function isBitwiseEquivalent(left, right)
{
let doubleArray = new Float64Array(1);
@@ -56,52 +48,76 @@
return true;
}
+ function cast(typedArrayConstructor, number)
+ {
+ var array = new typedArrayConstructor(1);
+ array[0] = number;
+ return array[0];
+ }
+
+ function bitwiseCast(typedArrayConstructor1, typedArrayConstructor2, value)
+ {
+ let typedArray1 = new typedArrayConstructor1(1);
+ let typedArray2 = new typedArrayConstructor2(typedArray1.buffer);
+ typedArray1[0] = value;
+ return typedArray2[0];
+ }
+
+ function castToHalf(number)
+ {
+ // FIXME: Make this math obey IEEE 754.
+ if (Number.isNaN(number))
+ return number
+ if (number > 65504)
+ return Number.POSITIVE_INFINITY;
+ if (number < -65504)
+ return Number.NEGATIVE_INFINITY;
+ if (number > 0 && number < Math.pow(2, -24))
+ return 0;
+ if (number < 0 && number > -Math.pow(2, -24))
+ return -0;
+ let doubleArray = new Float64Array(1);
+ let uintArray = new Uint8Array(doubleArray.buffer);
+ doubleArray[0] = number;
+ let sign = uintArray[7] & 0x80;
+ let exponent = ((uintArray[7] & 0x7f) << 4) | ((uintArray[6] & 0xf0) >>> 4);
+ let significand = ((uintArray[6] & 0x0f) << 6) | ((uintArray[5] & 0xfc) >>> 2);
+
+ if ((exponent - 1023) < -14) {
+ exponent = 0;
+ significand = (Math.abs(number) * Math.pow(2, 24)) >>> 0;
+ let value = Math.pow(2, -14) * significand / 1024;
+ if (sign != 0)
+ value *= -1;
+ return value;
+ }
+
+ doubleArray[0] = 0;
+
+ uintArray[7] |= sign;
+ uintArray[7] |= (exponent >>> 4);
+ uintArray[6] |= ((exponent << 4) & 0xf0);
+ uintArray[6] |= (significand >>> 6);
+ uintArray[5] |= ((significand << 2) & 0xfc);
+
+ return doubleArray[0];
+ }
+
this._map.set(
- "native typedef int",
+ "native typedef void",
type => {
- this.int = type;
- type.isPrimitive = true;
- type.isInt = true;
- type.isNumber = true;
- type.isSigned = true;
- type.canRepresent = value => isBitwiseEquivalent(value | 0, value);
- type.size = 1;
- type.defaultValue = 0;
- type.createLiteral = (origin, value) => IntLiteral.withType(origin, value | 0, type);
- type.successorValue = value => (value + 1) | 0;
- type.valuesEqual = (a, b) => a === b;
- type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
- type.formatValueFromIntLiteral = value => value | 0;
- type.formatValueFromUintLiteral = value => value | 0;
- type.allValues = function*() {
- for (let i = 0; i <= 0xffffffff; ++i) {
- let value = i | 0;
- yield {value: value, name: value};
- }
- };
+ this.void = type;
+ type.size = 0;
+ type.populateDefaultValue = () => { };
});
this._map.set(
- "native typedef uint",
+ "native typedef bool",
type => {
- this.uint = type;
+ this.bool = type;
type.isPrimitive = true;
- type.isInt = true;
- type.isNumber = true;
- type.isSigned = false;
- type.canRepresent = value => isBitwiseEquivalent(value >>> 0, value);
type.size = 1;
- type.defaultValue = 0;
- type.createLiteral = (origin, value) => IntLiteral.withType(origin, value >>> 0, type);
- type.successorValue = value => (value + 1) >>> 0;
- type.valuesEqual = (a, b) => a === b;
- type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
- type.formatValueFromIntLiteral = value => value >>> 0;
- type.formatValueFromUintLiteral = value => value >>> 0;
- type.allValues = function*() {
- for (let i = 0; i <= 0xffffffff; ++i)
- yield {value: i, name: i};
- };
+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, false);
});
this._map.set(
@@ -108,6 +124,7 @@
"native typedef uchar",
type => {
this.uchar = type;
+ type.isPrimitive = true;
type.isInt = true;
type.isNumber = true;
type.isSigned = false;
@@ -126,107 +143,250 @@
};
});
+
+ this._map.set(
+ "native typedef ushort",
+ type => {
+ this.ushort = type;
+ type.isPrimitive = true;
+ type.isInt = true;
+ type.isNumber = true;
+ type.isSigned = false;
+ type.canRepresent = value => isBitwiseEquivalent(value & 0xffff, value);
+ type.size = 1;
+ type.defaultValue = 0;
+ type.createLiteral = (origin, value) => IntLiteral.withType(origin, value & 0xffff, type);
+ type.successorValue = value => (value + 1) & 0xffff;
+ type.valuesEqual = (a, b) => a === b;
+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => value & 0xffff;
+ type.formatValueFromUintLiteral = value => value & 0xffff;
+ type.allValues = function*() {
+ for (let i = 0; i <= 0xffff; ++i)
+ yield {value: i, name: i};
+ };
+ });
+
this._map.set(
- "native typedef float",
- type => {
- this.float = type;
- type.isPrimitive = true;
- type.size = 1;
- type.isFloating = true;
- type.isNumber = true;
- type.canRepresent = value => isBitwiseEquivalent(Math.fround(value), value);
- type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
- type.formatValueFromIntLiteral = value => value;
- type.formatValueFromUintLiteral = value => value;
- type.formatValueFromFloatLiteral = value => Math.fround(value);
- });
+ "native typedef uint",
+ type => {
+ this.uint = type;
+ type.isPrimitive = true;
+ type.isInt = true;
+ type.isNumber = true;
+ type.isSigned = false;
+ type.canRepresent = value => isBitwiseEquivalent(value >>> 0, value);
+ type.size = 1;
+ type.defaultValue = 0;
+ type.createLiteral = (origin, value) => IntLiteral.withType(origin, value >>> 0, type);
+ type.successorValue = value => (value + 1) >>> 0;
+ type.valuesEqual = (a, b) => a === b;
+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => value >>> 0;
+ type.formatValueFromUintLiteral = value => value >>> 0;
+ type.allValues = function*() {
+ for (let i = 0; i <= 0xffffffff; ++i)
+ yield {value: i, name: i};
+ };
+ });
this._map.set(
- "native typedef bool",
- type => {
- this.bool = type;
- type.isPrimitive = true;
- type.size = 1;
- type.populateDefaultValue = (buffer, offset) => buffer.set(offset, false);
- });
+ "native typedef char",
+ type => {
+ this.char = type;
+ type.isPrimitive = true;
+ type.isInt = true;
+ type.isNumber = true;
+ type.isSigned = true;
+ type.canRepresent = value => isBitwiseEquivalent(cast(Int8Array, value), value);
+ type.size = 1;
+ type.defaultValue = 0;
+ type.createLiteral = (origin, value) => IntLiteral.withType(origin, cast(Int8Array, value), type);
+ type.successorValue = value => cast(Int8Array, value + 1);
+ type.valuesEqual = (a, b) => a === b;
+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => cast(Int8Array, value);
+ type.formatValueFromUintLiteral = value => cast(Int8Array, value);
+ type.allValues = function*() {
+ for (let i = 0; i <= 0xff; ++i) {
+ let value = cast(Int8Array, i);
+ yield {value: value, name: value};
+ }
+ };
+ });
+ this._map.set(
+ "native typedef short",
+ type => {
+ this.short = type;
+ type.isPrimitive = true;
+ type.isInt = true;
+ type.isNumber = true;
+ type.isSigned = true;
+ type.canRepresent = value => isBitwiseEquivalent(cast(Int16Array, value), value);
+ type.size = 1;
+ type.defaultValue = 0;
+ type.createLiteral = (origin, value) => IntLiteral.withType(origin, cast(Int16Array, value), type);
+ type.successorValue = value => cast(Int16Array, value + 1);
+ type.valuesEqual = (a, b) => a === b;
+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => cast(Int16Array, value);
+ type.formatValueFromUintLiteral = value => cast(Int16Array, value);
+ type.allValues = function*() {
+ for (let i = 0; i <= 0xffff; ++i) {
+ let value = cast(Int16Array, i);
+ yield {value: value, name: value};
+ }
+ };
+ });
+
+ this._map.set(
+ "native typedef int",
+ type => {
+ this.int = type;
+ type.isPrimitive = true;
+ type.isInt = true;
+ type.isNumber = true;
+ type.isSigned = true;
+ type.canRepresent = value => isBitwiseEquivalent(value | 0, value);
+ type.size = 1;
+ type.defaultValue = 0;
+ type.createLiteral = (origin, value) => IntLiteral.withType(origin, value | 0, type);
+ type.successorValue = value => (value + 1) | 0;
+ type.valuesEqual = (a, b) => a === b;
+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => value | 0;
+ type.formatValueFromUintLiteral = value => value | 0;
+ type.allValues = function*() {
+ for (let i = 0; i <= 0xffffffff; ++i) {
+ let value = i | 0;
+ yield {value: value, name: value};
+ }
+ };
+ });
+
+ this._map.set(
+ "native typedef half",
+ type => {
+ this.half = type;
+ type.isPrimitive = true;
+ type.size = 1;
+ type.isFloating = true;
+ type.isNumber = true;
+ type.canRepresent = value => isBitwiseEquivalent(castToHalf(value), value);
+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => value;
+ type.formatValueFromUintLiteral = value => value;
+ type.formatValueFromFloatLiteral = value => castToHalf(value);
+ });
+
+ this._map.set(
+ "native typedef float",
+ type => {
+ this.float = type;
+ type.isPrimitive = true;
+ type.size = 1;
+ type.isFloating = true;
+ type.isNumber = true;
+ type.canRepresent = value => isBitwiseEquivalent(Math.fround(value), value);
+ type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+ type.formatValueFromIntLiteral = value => value;
+ type.formatValueFromUintLiteral = value => value;
+ type.formatValueFromFloatLiteral = value => Math.fround(value);
+ });
+
+ this._map.set(
+ "native typedef atomic_int",
+ type => {
+ this.atomic_int = type;
+ });
+
+ this._map.set(
+ "native typedef atomic_uint",
+ type => {
+ this.atomic_uint = type;
+ });
+
for (let vectorType of VectorElementTypes) {
- for (let vectorSize of VectorElementSizes)
- this._map.set(`native typedef vector<${vectorType}, ${vectorSize}>`, type => {});
+ for (let vectorSize of VectorElementSizes) {
+ this._map.set(`native typedef vector<${vectorType}, ${vectorSize}>`, type => {
+ this[`vector<${vectorType}, ${vectorSize}>`] = type;
+ });
+ }
}
-
+
this._map.set(
"native operator int(uint)",
func => {
func.implementation = ([value]) => EPtr.box(value.loadValue() | 0);
});
-
+
this._map.set(
"native operator int(uchar)",
func => {
func.implementation = ([value]) => EPtr.box(value.loadValue() | 0);
});
-
+
this._map.set(
"native operator int(float)",
func => {
func.implementation = ([value]) => EPtr.box(value.loadValue() | 0);
});
-
+
this._map.set(
"native operator uint(int)",
func => {
func.implementation = ([value]) => EPtr.box(value.loadValue() >>> 0);
});
-
+
this._map.set(
"native operator uint(uchar)",
func => {
func.implementation = ([value]) => EPtr.box(value.loadValue() >>> 0);
});
-
+
this._map.set(
"native operator uint(float)",
func => {
func.implementation = ([value]) => EPtr.box(value.loadValue() >>> 0);
});
-
+
this._map.set(
"native operator uchar(int)",
func => {
func.implementation = ([value]) => EPtr.box(value.loadValue() & 0xff);
});
-
+
this._map.set(
"native operator uchar(uint)",
func => {
func.implementation = ([value]) => EPtr.box(value.loadValue() & 0xff);
});
-
+
this._map.set(
"native operator uchar(float)",
func => {
func.implementation = ([value]) => EPtr.box(value.loadValue() & 0xff);
});
-
+
this._map.set(
"native operator float(int)",
func => {
func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
});
-
+
this._map.set(
"native operator float(uint)",
func => {
func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
});
-
+
this._map.set(
"native operator float(uchar)",
func => {
func.implementation = ([value]) => EPtr.box(Math.fround(value.loadValue()));
});
-
+
this._map.set(
"native int operator+(int,int)",
func => {
@@ -233,7 +393,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() + right.loadValue()) | 0);
});
-
+
this._map.set(
"native uint operator+(uint,uint)",
func => {
@@ -240,7 +400,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() + right.loadValue()) >>> 0);
});
-
+
this._map.set(
"native float operator+(float,float)",
func => {
@@ -247,7 +407,7 @@
func.implementation = ([left, right]) =>
EPtr.box(Math.fround(left.loadValue() + right.loadValue()));
});
-
+
this._map.set(
"native int operator-(int,int)",
func => {
@@ -254,7 +414,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() - right.loadValue()) | 0);
});
-
+
this._map.set(
"native uint operator-(uint,uint)",
func => {
@@ -261,7 +421,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() - right.loadValue()) >>> 0);
});
-
+
this._map.set(
"native float operator-(float,float)",
func => {
@@ -268,7 +428,7 @@
func.implementation = ([left, right]) =>
EPtr.box(Math.fround(left.loadValue() - right.loadValue()));
});
-
+
this._map.set(
"native int operator*(int,int)",
func => {
@@ -276,7 +436,7 @@
return EPtr.box((left.loadValue() * right.loadValue()) | 0);
};
});
-
+
this._map.set(
"native uint operator*(uint,uint)",
func => {
@@ -283,7 +443,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() * right.loadValue()) >>> 0);
});
-
+
this._map.set(
"native float operator*(float,float)",
func => {
@@ -290,7 +450,7 @@
func.implementation = ([left, right]) =>
EPtr.box(Math.fround(left.loadValue() * right.loadValue()));
});
-
+
this._map.set(
"native int operator/(int,int)",
func => {
@@ -297,7 +457,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() / right.loadValue()) | 0);
});
-
+
this._map.set(
"native uint operator/(uint,uint)",
func => {
@@ -304,7 +464,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() / right.loadValue()) >>> 0);
});
-
+
this._map.set(
"native int operator&(int,int)",
func => {
@@ -311,7 +471,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() & right.loadValue());
});
-
+
this._map.set(
"native uint operator&(uint,uint)",
func => {
@@ -318,7 +478,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() & right.loadValue()) >>> 0);
});
-
+
this._map.set(
"native int operator|(int,int)",
func => {
@@ -325,7 +485,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() | right.loadValue());
});
-
+
this._map.set(
"native uint operator|(uint,uint)",
func => {
@@ -332,7 +492,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() | right.loadValue()) >>> 0);
});
-
+
this._map.set(
"native int operator^(int,int)",
func => {
@@ -339,7 +499,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() ^ right.loadValue());
});
-
+
this._map.set(
"native uint operator^(uint,uint)",
func => {
@@ -346,7 +506,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() ^ right.loadValue()) >>> 0);
});
-
+
this._map.set(
"native int operator<<(int,uint)",
func => {
@@ -353,7 +513,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() << right.loadValue());
});
-
+
this._map.set(
"native uint operator<<(uint,uint)",
func => {
@@ -360,7 +520,7 @@
func.implementation = ([left, right]) =>
EPtr.box((left.loadValue() << right.loadValue()) >>> 0);
});
-
+
this._map.set(
"native int operator>>(int,uint)",
func => {
@@ -367,7 +527,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() >> right.loadValue());
});
-
+
this._map.set(
"native uint operator>>(uint,uint)",
func => {
@@ -374,19 +534,19 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() >>> right.loadValue());
});
-
+
this._map.set(
"native int operator~(int)",
func => {
func.implementation = ([value]) => EPtr.box(~value.loadValue());
});
-
+
this._map.set(
"native uint operator~(uint)",
func => {
func.implementation = ([value]) => EPtr.box((~value.loadValue()) >>> 0);
});
-
+
this._map.set(
"native float operator/(float,float)",
func => {
@@ -393,7 +553,7 @@
func.implementation = ([left, right]) =>
EPtr.box(Math.fround(left.loadValue() / right.loadValue()));
});
-
+
this._map.set(
"native bool operator==(int,int)",
func => {
@@ -400,7 +560,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() == right.loadValue());
});
-
+
this._map.set(
"native bool operator==(uint,uint)",
func => {
@@ -407,7 +567,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() == right.loadValue());
});
-
+
this._map.set(
"native bool operator==(bool,bool)",
func => {
@@ -414,7 +574,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() == right.loadValue());
});
-
+
this._map.set(
"native bool operator==(float,float)",
func => {
@@ -421,7 +581,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() == right.loadValue());
});
-
+
this._map.set(
"native bool operator<(int,int)",
func => {
@@ -428,7 +588,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() < right.loadValue());
});
-
+
this._map.set(
"native bool operator<(uint,uint)",
func => {
@@ -435,7 +595,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() < right.loadValue());
});
-
+
this._map.set(
"native bool operator<(float,float)",
func => {
@@ -442,7 +602,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() < right.loadValue());
});
-
+
this._map.set(
"native bool operator<=(int,int)",
func => {
@@ -449,7 +609,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() <= right.loadValue());
});
-
+
this._map.set(
"native bool operator<=(uint,uint)",
func => {
@@ -456,7 +616,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() <= right.loadValue());
});
-
+
this._map.set(
"native bool operator<=(float,float)",
func => {
@@ -463,7 +623,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() <= right.loadValue());
});
-
+
this._map.set(
"native bool operator>(int,int)",
func => {
@@ -470,7 +630,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() > right.loadValue());
});
-
+
this._map.set(
"native bool operator>(uint,uint)",
func => {
@@ -477,7 +637,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() > right.loadValue());
});
-
+
this._map.set(
"native bool operator>(float,float)",
func => {
@@ -484,7 +644,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() > right.loadValue());
});
-
+
this._map.set(
"native bool operator>=(int,int)",
func => {
@@ -491,7 +651,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() >= right.loadValue());
});
-
+
this._map.set(
"native bool operator>=(uint,uint)",
func => {
@@ -498,7 +658,7 @@
func.implementation = ([left, right]) =>
EPtr.box(left.loadValue() >= right.loadValue());
});
-
+
this._map.set(
"native bool operator>=(float,float)",
func => {
@@ -538,7 +698,7 @@
for (let setter of BuiltinVectorSetter.functions())
this._map.set(setter.toString(), func => setter.instantiateImplementation(func));
}
-
+
add(thing)
{
let intrinsic = this._map.get(thing.toString());
Modified: trunk/Tools/WebGPUShadingLanguageRI/NameContext.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/NameContext.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/NameContext.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -69,11 +69,33 @@
return;
}
+ if (thing.kind == Type) {
+ this._set.add(thing);
+ if (thing.name == "vector") {
+ let array = this._map.get(thing.name);
+ if (!array) {
+ array = [];
+ array.kind = Type;
+ this._map.set(thing.name, array);
+ }
+ if (array.kind != Type)
+ throw new WTypeError(thing.origin.originString, "Cannot reuse type name for function: " + thing.name);
+ array.push(thing);
+ return;
+ } else {
+ if (this._map.has(thing.name))
+ throw new WTypeError(thing.origin.originString, "Duplicate name: " + thing.name);
+ this._map.set(thing.name, thing);
+ }
+ return;
+ }
+
if (this._map.has(thing.name))
throw new WTypeError(thing.origin.originString, "Duplicate name: " + thing.name);
this._set.add(thing);
this._map.set(thing.name, thing);
+
}
get(kind, name)
@@ -102,6 +124,10 @@
for (let func of thing)
yield func;
return;
+ } else if (thing.kind === Type && (thing instanceof Array)) {
+ for (let type of thing)
+ yield type;
+ return;
}
yield thing;
}
@@ -163,8 +189,8 @@
{
for (let value of this._map.values()) {
if (value instanceof Array) {
- for (let func of value)
- yield func;
+ for (let thing of value)
+ yield thing;
continue;
}
yield value;
Modified: trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/NameResolver.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -120,12 +120,19 @@
visitTypeRef(node)
{
+ super.visitTypeRef(node);
let type = node.type;
if (!type) {
type = this._nameContext.get(Type, node.name);
if (!type)
throw new WTypeError(node.origin.originString, "Could not find type named " + node.name);
- node.type = type;
+ if (type instanceof Array) {
+ // Type unification requires the .type value to be set already, so we can eagerly set it now.
+ for (let overload of type)
+ Node.visit(overload, this);
+ node.resolve(type);
+ } else
+ node.type = type;
}
}
@@ -208,9 +215,4 @@
super.visitCallExpression(node);
}
-
- visitVectorType(node)
- {
- node.elementType.visit(this);
- }
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/NativeType.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/NativeType.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/NativeType.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -25,11 +25,14 @@
"use strict";
class NativeType extends Type {
- constructor(origin, name)
+ constructor(origin, name, typeArguments)
{
+ if (!(typeArguments instanceof Array))
+ throw new Error("type parameters not array: " + typeArguments);
super();
this._origin = origin;
this._name = name;
+ this._typeArguments = typeArguments;
this._isNumber = false;
this._isInt = false;
this._isFloating = false;
@@ -38,6 +41,7 @@
get origin() { return this._origin; }
get name() { return this._name; }
+ get typeArguments() { return this._typeArguments; }
get isNative() { return true; }
// We let Intrinsics.js set these as it likes.
@@ -52,19 +56,18 @@
toString()
{
- return `native typedef ${this.name}`;
+ let result = `native typedef ${this.name}`;
+ if (this.typeArguments.length)
+ result += "<" + this.typeArguments.join(",") + ">";
+ return result;
}
static create(origin, name, typeArguments)
{
- // FIXME: For native types like Texture1D this should resolve the type to something concrete by changing the type name.
- if (typeArguments.length)
- throw new WTypeError(origin.originString, `${name}<${typeArguments.join(",")}>: Support for native types with type arguments is currently unimplemented.`);
+ if (name == "vector")
+ return new VectorType(origin, name, typeArguments);
- if (allVectorTypeNames().indexOf(name) > -1)
- return new VectorType(origin, name);
-
- return new NativeType(origin, name);
+ return new NativeType(origin, name, typeArguments);
}
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Prepare.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/Prepare.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/Prepare.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -40,7 +40,6 @@
}
foldConstexprs(program);
- removeTypeArguments(program);
let nameResolver = createNameResolver(program);
resolveNamesInTypes(program, nameResolver);
@@ -54,6 +53,7 @@
synthesizeDefaultConstructorOperator(program);
resolveNamesInFunctions(program, nameResolver);
resolveTypeDefsInFunctions(program);
+ checkTypesWithArguments(program);
check(program);
checkLiteralTypes(program);
@@ -66,6 +66,7 @@
checkLoops(program);
checkRecursion(program);
checkProgramWrapped(program);
+ checkTypesWithArguments(program);
findHighZombies(program);
program.visit(new StructLayoutBuilder());
inline(program);
Modified: trunk/Tools/WebGPUShadingLanguageRI/Program.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/Program.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/Program.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -48,19 +48,25 @@
if (statement instanceof Func) {
let array = this._functions.get(statement.name);
if (!array)
- this._functions.set(statement.name, array = []);
+ this.functions.set(statement.name, array = []);
array.push(statement);
- } else if (statement instanceof Type)
- this._types.set(statement.name, statement);
- else
+ } else if (statement instanceof Type) {
+ if (statement.isNative && statement.name == "vector") {
+ let array = this.types.get(statement.name);
+ if (!array)
+ this.types.set(statement.name, array = []);
+ array.push(statement);
+ } else
+ this.types.set(statement.name, statement);
+ } else
throw new Error("Statement is not a function or type: " + statement);
- this._topLevelStatements.push(statement);
- this._globalNameContext.add(statement);
+ this.topLevelStatements.push(statement);
+ this.globalNameContext.add(statement);
}
toString()
{
- if (!this._topLevelStatements.length)
+ if (!this.topLevelStatements.length)
return "";
return this._topLevelStatements.join(";") + ";";
}
Deleted: trunk/Tools/WebGPUShadingLanguageRI/RemoveTypeArguments.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/RemoveTypeArguments.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/RemoveTypeArguments.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-"use strict";
-
-function removeTypeArguments(program)
-{
- class RemoveTypeArguments extends Visitor {
- static resolveNameAndArguments(node)
- {
- if (!node.typeArguments)
- return node.name;
-
- switch (node.name) {
- case "vector":
- if (node.typeArguments.length != 2)
- throw new WSyntaxError(node.originString, `${node.name} should have 2 type arguments, got ${node.typeArguments.length}.`);
-
- const elementTypeName = node.typeArguments[0].name;
- const lengthValue = node.typeArguments[1].value;
-
- if (VectorElementTypes.indexOf(elementTypeName) < 0)
- throw new WSyntaxError(node.originString, `${elementTypeName} is not a valid vector element type.`);
- if (VectorElementSizes.indexOf(lengthValue) < 0)
- throw new WSyntaxError(node.originString, `${lengthValue} is not a valid size for vectors with element type ${elementTypeName}.`);
-
- return `${elementTypeName}${lengthValue}`;
- // FIXME: Further cases for matrices, textures, etc.
- default:
- if (node.typeArguments.length)
- throw new WSyntaxError(`${node.name}${arguments.join(", ")} is not a permitted generic type or function`);
- return node.name;
- }
- }
-
- visitTypeRef(node)
- {
- node._name = RemoveTypeArguments.resolveNameAndArguments(node);
- node._typeArguments = null;
- }
- }
-
- program.visit(new RemoveTypeArguments());
-}
Modified: trunk/Tools/WebGPUShadingLanguageRI/ResolveNames.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/ResolveNames.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/ResolveNames.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -31,8 +31,13 @@
function resolveNamesInTypes(program, nameResolver)
{
- for (let type of program.types.values())
- nameResolver.doStatement(type);
+ for (let type of program.types.values()) {
+ if (type instanceof Array) {
+ for (let constituentType of type)
+ nameResolver.doStatement(constituentType);
+ } else
+ nameResolver.doStatement(type);
+ }
}
function resolveNamesInFunctions(program, nameResolver)
Modified: trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/ResolveOverloadImpl.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -100,3 +100,28 @@
return {failures: ambiguityList.map(overload => new OverloadResolutionFailure(overload.func, message))};
}
+
+function resolveTypeOverloadImpl(types, typeArguments)
+{
+ if (!types)
+ throw new Error("Null types; that should have been caught by the caller.");
+
+ let failures = [];
+ let successes = [];
+ for (let type of types) {
+ let overload = inferTypesForTypeArguments(type, typeArguments);
+ if (overload.failure)
+ failures.push(overload.failure);
+ else
+ successes.push(overload);
+ }
+
+ if (!successes.length)
+ return {failures: failures};
+
+ if (successes.length == 1)
+ return successes[0];
+
+ let message = "Ambiguous overload - types mutually applicable";
+ return {failures: successes.map(overload => new TypeOverloadResolutionFailure(overload.type, message))};
+}
Modified: trunk/Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -27,8 +27,13 @@
function resolveTypeDefsInTypes(program)
{
let resolver = new TypeDefResolver();
- for (let type of program.types.values())
- type.visit(resolver);
+ for (let type of program.types.values()) {
+ if (type instanceof Array) {
+ for (let constituentType of type)
+ constituentType.visit(resolver);
+ } else
+ type.visit(resolver);
+ }
}
function resolveTypeDefsInFunctions(program)
Modified: trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -97,7 +97,7 @@
visitTypeRef(node)
{
- let result = new TypeRef(node.origin, node.name);
+ let result = new TypeRef(node.origin, node.name, node.typeArguments.map(argument => argument.visit(this)));
if (node.type)
result.type = Node.visit(node.type, this);
return result;
@@ -382,7 +382,7 @@
visitVectorType(node)
{
- const vecType = new VectorType(node.origin, node.name);
+ const vecType = new VectorType(node.origin, node.name, node.typeArguments.map(argument => argument.visit(this)));
vecType._elementType = node.elementType.visit(this);
return vecType;
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/SPIRV.html (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/SPIRV.html 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/SPIRV.html 2018-08-23 19:52:16 UTC (rev 235237)
@@ -43,6 +43,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
@@ -116,7 +117,6 @@
<script src=""
<script src=""
<script src=""
- <script src=""
<script src=""
<script src=""
<script src=""
@@ -140,6 +140,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -33,17 +33,70 @@
native typedef void;
native typedef bool;
native typedef uchar;
+native typedef ushort;
native typedef uint;
+native typedef char;
+native typedef short;
native typedef int;
+native typedef half;
native typedef float;
+native typedef atomic_int;
+native typedef atomic_uint;
-// FIXME: Add support for these types to Intrinsics.js
-// native typedef ushort;
-// native typedef char;
-// native typedef short;
-// native typedef half;
-// native typedef atomic_int;
-// native typedef atomic_uint;
+native typedef vector<bool, 2>;
+typedef bool2 = vector<bool, 2>;
+native typedef vector<bool, 3>;
+typedef bool3 = vector<bool, 3>;
+native typedef vector<bool, 4>;
+typedef bool4 = vector<bool, 4>;
+native typedef vector<uchar, 2>;
+typedef uchar2 = vector<uchar, 2>;
+native typedef vector<uchar, 3>;
+typedef uchar3 = vector<uchar, 3>;
+native typedef vector<uchar, 4>;
+typedef uchar4 = vector<uchar, 4>;
+native typedef vector<ushort, 2>;
+typedef ushort2 = vector<ushort, 2>;
+native typedef vector<ushort, 3>;
+typedef ushort3 = vector<ushort, 3>;
+native typedef vector<ushort, 4>;
+typedef ushort4 = vector<ushort, 4>;
+native typedef vector<uint, 2>;
+typedef uint2 = vector<uint, 2>;
+native typedef vector<uint, 3>;
+typedef uint3 = vector<uint, 3>;
+native typedef vector<uint, 4>;
+typedef uint4 = vector<uint, 4>;
+native typedef vector<char, 2>;
+typedef char2 = vector<char, 2>;
+native typedef vector<char, 3>;
+typedef char3 = vector<char, 3>;
+native typedef vector<char, 4>;
+typedef char4 = vector<char, 4>;
+native typedef vector<short, 2>;
+typedef short2 = vector<short, 2>;
+native typedef vector<short, 3>;
+typedef short3 = vector<short, 3>;
+native typedef vector<short, 4>;
+typedef short4 = vector<short, 4>;
+native typedef vector<int, 2>;
+typedef int2 = vector<int, 2>;
+native typedef vector<int, 3>;
+typedef int3 = vector<int, 3>;
+native typedef vector<int, 4>;
+typedef int4 = vector<int, 4>;
+native typedef vector<half, 2>;
+typedef half2 = vector<half, 2>;
+native typedef vector<half, 3>;
+typedef half3 = vector<half, 3>;
+native typedef vector<half, 4>;
+typedef half4 = vector<half, 4>;
+native typedef vector<float, 2>;
+typedef float2 = vector<float, 2>;
+native typedef vector<float, 3>;
+typedef float3 = vector<float, 3>;
+native typedef vector<float, 4>;
+typedef float4 = vector<float, 4>;
native operator int(uint);
native operator int(uchar);
@@ -147,28 +200,12 @@
{
return !value;
}
-
-native typedef uchar2;
-native typedef uchar3;
-native typedef uchar4;
-
-native typedef uint2;
-native typedef uint3;
-native typedef uint4;
-
-native typedef int2;
-native typedef int3;
-native typedef int4;
-
-native typedef float2;
-native typedef float3;
-native typedef float4;
`;
// FIXME: Once the standard library has been replaced with a new version, this comments should be removed.
// This list is used to restrict the availability of vector types available in the langauge.
// Permissible vector element types must appear in this list and in the standard library
-const VectorElementTypes = [ /*"bool",*/ "uchar", /*"char", "ushort", "short",*/ "uint", "int", /* "half", */"float" ];
+const VectorElementTypes = [ "bool", "uchar", "char", "ushort", "short", "uint", "int", "half", "float" ];
const VectorElementSizes = [ 2, 3, 4 ];
function allVectorTypeNames()
Modified: trunk/Tools/WebGPUShadingLanguageRI/StatementCloner.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/StatementCloner.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/StatementCloner.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -50,7 +50,7 @@
visitNativeType(node)
{
- return new NativeType(node.origin, node.name);
+ return new NativeType(node.origin, node.name, node.typeArguments.map(argument => argument.visit(this)));
}
visitTypeDef(node)
Modified: trunk/Tools/WebGPUShadingLanguageRI/SynthesizeDefaultConstructorOperator.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/SynthesizeDefaultConstructorOperator.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/SynthesizeDefaultConstructorOperator.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -45,6 +45,12 @@
types.add(node);
super.visitElementalType(node);
}
+
+ visitVectorType(node)
+ {
+ types.add(node);
+ super.visitVectorType(node);
+ }
}
program.visit(new FindAllTypes());
Modified: trunk/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -51,7 +51,7 @@
function createTypeRef()
{
- return TypeRef.instantiate(type);
+ return TypeRef.wrap(type);
}
let isCast = false;
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.html 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html 2018-08-23 19:52:16 UTC (rev 235237)
@@ -37,6 +37,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -110,7 +111,6 @@
<script src=""
<script src=""
<script src=""
-<script src=""
<script src=""
<script src=""
<script src=""
@@ -134,6 +134,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -2881,7 +2881,7 @@
}
fragment Boo bar(Foo stageIn)
{
- return boo();
+ return Boo();
}
`),
(e) => e instanceof WTypeError);
@@ -2904,7 +2904,7 @@
tests.vectorTypeSyntax = function()
{
- const program = doPrep(`
+ let program = doPrep(`
int foo2()
{
int2 x;
@@ -2939,7 +2939,26 @@
checkInt(program, callFunction(program, "foo2", []), 4);
checkInt(program, callFunction(program, "foo3", []), 5);
checkInt(program, callFunction(program, "foo4", []), 6);
+ checkBool(program, callFunction(program, "vec2OperatorCast", []), true);
+ program = doPrep(`
+ typedef i = int;
+ int foo2()
+ {
+ int2 x;
+ vector<i, 2> z = int2(3, 4);
+ x = z;
+ return x.y;
+ }
+
+ bool vec2OperatorCast()
+ {
+ int2 x = vector<i,2>(1, 2);
+ vector<i, 2> y = int2(1, 2);
+ return x == y && x.x == 1 && x.y == 2 && y.x == 1 && y.y == 2;
+ }`);
+
+ checkInt(program, callFunction(program, "foo2", []), 4);
checkBool(program, callFunction(program, "vec2OperatorCast", []), true);
}
Copied: trunk/Tools/WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js (from rev 235236, trunk/Tools/WebGPUShadingLanguageRI/ResolveTypeDefs.js) (0 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/TypeOverloadResolutionFailure.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+"use strict";
+
+class TypeOverloadResolutionFailure {
+ constructor(type, reason)
+ {
+ this._type = type;
+ this._reason = reason;
+ }
+
+ get type() { return this._type; }
+ get reason() { return this._reason; }
+
+ toString()
+ {
+ return this.type.toString() + " did not match because: " + this.reason;
+ }
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/TypeRef.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/TypeRef.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/TypeRef.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -25,7 +25,7 @@
"use strict";
class TypeRef extends Type {
- constructor(origin, name, typeArguments = null)
+ constructor(origin, name, typeArguments = [])
{
super();
this._origin = origin;
@@ -38,17 +38,14 @@
{
if (type instanceof TypeRef)
return type;
- let result = new TypeRef(type.origin, type.name);
+ let result;
+ if (type instanceof NativeType)
+ result = new TypeRef(type.origin, type.name, type.typeArguments);
+ else
+ result = new TypeRef(type.orgin, type.name);
result.type = type;
return result;
}
-
- static instantiate(type)
- {
- let result = new TypeRef(type.origin, type.name);
- result.type = type;
- return result;
- }
get origin() { return this._origin; }
get name() { return this._name; }
@@ -64,6 +61,39 @@
this._type = newType;
}
+ resolve(possibleOverloads)
+ {
+ if (!possibleOverloads)
+ throw new WTypeError(this.origin.originString, "Did not find any types named " + this.name);
+
+ let failures = [];
+ let overload = resolveTypeOverloadImpl(possibleOverloads, this.typeArguments);
+
+ if (!overload.type) {
+ failures.push(...overload.failures);
+ let message = "Did not find type named " + this.name + " for type arguments ";
+ message += "(" + this.typeArguments + ")";
+ if (failures.length)
+ message += ", but considered:\n" + failures.join("\n")
+ throw new WTypeError(this.origin.originString, message);
+ }
+
+ for (let i = 0; i < this.typeArguments.length; ++i) {
+ let typeArgument = this.typeArguments[i];
+ let resolvedTypeArgument = overload.type.typeArguments[i];
+ let result = typeArgument.equalsWithCommit(resolvedTypeArgument);
+ if (!result)
+ throw new Error("At " + this.origin.originString + " argument types for Type and TypeRef not equal: argument type = " + typeArgument + ", resolved type argument = " + resolvedTypeArgument);
+ if (resolvedTypeArgument.constructor.name == "GenericLiteral") {
+ result = typeArgument.type.equalsWithCommit(resolvedTypeArgument.type);
+ if (!result)
+ throw new Error("At " + this.origin.originString + " argument types for Type and TypeRef not equal: argument type = " + typeArgument + ", resolved type argument = " + resolvedTypeArgument);
+ }
+
+ }
+ this.type = overload.type;
+ }
+
get unifyNode()
{
if (!this.type)
@@ -99,7 +129,10 @@
{
if (!this.name)
return this.type.toString();
- return this.name;
+ let result = this.name;
+ if (this.typeArguments.length > 0)
+ result += "<" + this.typeArguments.map(argument => argument.toString()).join(",") + ">";
+ return result;
}
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/UnificationContext.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/UnificationContext.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/UnificationContext.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -92,6 +92,19 @@
verify()
{
+ // We do a two-phase pre-verification. This gives literals a chance to select a more specific type.
+ let preparations = [];
+ for (let node of this.nodes) {
+ let preparation = node.prepareToVerify(this);
+ if (preparation)
+ preparations.push(preparation);
+ }
+ for (let preparation of preparations) {
+ let result = preparation();
+ if (!result.result)
+ return result;
+ }
+
for (let typeArgument of this.typeArguments()) {
let result = typeArgument.verifyAsArgument(this);
if (!result.result)
Modified: trunk/Tools/WebGPUShadingLanguageRI/VectorType.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/VectorType.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/VectorType.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -25,19 +25,14 @@
"use strict";
class VectorType extends NativeType {
- constructor(origin, name)
+ constructor(origin, name, typeArguments)
{
- super(origin, name);
- const match = /^([A-z]+)([0-9])$/.exec(name);
- if (!match)
- throw new WTypeError(origin.originString, `${name} doesn't match the format for vector type names.'`);
-
- this._elementType = new TypeRef(origin, match[1]);
- this._numElementsValue = parseInt(match[2]);
+ super(origin, name, typeArguments);
}
- get elementType() { return this._elementType; }
- get numElementsValue() { return this._numElementsValue; }
+ get elementType() { return this.typeArguments[0]; }
+ get numElements() { return this.typeArguments[1]; }
+ get numElementsValue() { return this.numElements.value; }
get size() { return this.elementType.size * this.numElementsValue; }
unifyImpl(unificationContext, other)
@@ -59,7 +54,7 @@
toString()
{
- return `native typedef ${this.elementType}${this.numElementsValue}`;
+ return `native typedef vector<${this.elementType}, ${this.numElementsValue}>`;
}
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Visitor.js (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2018-08-23 19:52:16 UTC (rev 235237)
@@ -68,10 +68,14 @@
visitTypeRef(node)
{
+ for (let typeArgument of node.typeArguments)
+ typeArgument.visit(this);
}
visitNativeType(node)
{
+ for (let typeArgument of node.typeArguments)
+ typeArgument.visit(this);
}
visitTypeDef(node)
@@ -327,6 +331,7 @@
visitVectorType(node)
{
node.elementType.visit(this);
+ node.numElements.visit(this);
}
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/index.html (235236 => 235237)
--- trunk/Tools/WebGPUShadingLanguageRI/index.html 2018-08-23 19:51:22 UTC (rev 235236)
+++ trunk/Tools/WebGPUShadingLanguageRI/index.html 2018-08-23 19:52:16 UTC (rev 235237)
@@ -38,6 +38,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -110,7 +111,6 @@
<script src=""
<script src=""
<script src=""
-<script src=""
<script src=""
<script src=""
<script src=""
@@ -134,6 +134,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""