Diff
Modified: trunk/Tools/ChangeLog (221887 => 221888)
--- trunk/Tools/ChangeLog 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/ChangeLog 2017-09-11 22:53:36 UTC (rev 221888)
@@ -1,3 +1,72 @@
+2017-09-11 Filip Pizlo <[email protected]>
+
+ WSL Substitution should probably wrap type variables of substituted types rather than just wrapping the whole type
+ https://bugs.webkit.org/show_bug.cgi?id=176677
+
+ Reviewed by Mylex Maxfield.
+
+ This adds a checker that verifies that all type references and variable references are wrapped.
+
+ Then this fixes errors found by that checker by making Substitution auto-wrap replacements rather than
+ manually wrapping the outer type (for types) and cloning (for values).
+
+ * WebGPUShadingLanguageRI/All.js:
+ * WebGPUShadingLanguageRI/AutoWrapper.js: Added.
+ (AutoWrapper.prototype.visitVariableRef):
+ (AutoWrapper.prototype.visitTypeRef):
+ (AutoWrapper.prototype.visitConstexprTypeParameter):
+ (AutoWrapper.prototype.visitFuncParameter):
+ (AutoWrapper.prototype.visitVariableDecl):
+ (AutoWrapper.prototype.visitStructType):
+ (AutoWrapper.prototype.visitNativeType):
+ (AutoWrapper):
+ * WebGPUShadingLanguageRI/CheckWrapped.js:
+ (checkExpressionWrapped):
+ (checkProgramWrapped):
+ (checkWrapped): Deleted.
+ * WebGPUShadingLanguageRI/Checker.js:
+ * WebGPUShadingLanguageRI/ExpressionFinder.js: Added.
+ (ExpressionFinder):
+ (ExpressionFinder.prototype.visitFunc):
+ (ExpressionFinder.prototype.visitFuncParameter):
+ (ExpressionFinder.prototype.visitConstexprTypeParameter):
+ (ExpressionFinder.prototype.visitAssignment):
+ (ExpressionFinder.prototype.visitCallExpression):
+ (ExpressionFinder.prototype.visitReturn):
+ (ExpressionFinder.prototype.visitWhileLoop):
+ (ExpressionFinder.prototype.visitDoWhileLoop):
+ (ExpressionFinder.prototype.visitIfStatement):
+ (ExpressionFinder.prototype.visitForLoop):
+ (ExpressionFinder.prototype.visitVariableDecl):
+ * WebGPUShadingLanguageRI/NativeFuncInstance.js:
+ (NativeFuncInstance):
+ * WebGPUShadingLanguageRI/Node.js:
+ (Node.prototype.substituteToUnification):
+ (Node):
+ (Node.prototype.clone): Deleted.
+ * WebGPUShadingLanguageRI/Prepare.js:
+ (prepare):
+ * WebGPUShadingLanguageRI/StructLayoutBuilder.js:
+ (StructLayoutBuilder.prototype.visitReferenceType):
+ (StructLayoutBuilder.prototype.visitField):
+ (StructLayoutBuilder):
+ * WebGPUShadingLanguageRI/Substitution.js:
+ (Substitution):
+ (Substitution.prototype.visitTypeRef):
+ (Substitution.prototype.visitVariableRef):
+ * WebGPUShadingLanguageRI/Test.html:
+ * WebGPUShadingLanguageRI/Test.js:
+ (TEST_chainConstexpr):
+ (TEST_chainGeneric):
+ (TEST_chainStruct):
+ (TEST_chainStructInvalid):
+ * WebGPUShadingLanguageRI/Visitor.js:
+ (Visitor.prototype.visitNativeTypeInstance):
+ * WebGPUShadingLanguageRI/WrapChecker.js:
+ (WrapChecker.prototype._foundUnwrapped.originString):
+ (WrapChecker.prototype._foundUnwrapped):
+ (WrapChecker):
+
2017-09-11 Ryan Haddad <[email protected]>
Fix multiple master.cfg unit test failures.
Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -37,6 +37,7 @@
load("ArrayRefType.js");
load("ArrayType.js");
load("Assignment.js");
+load("AutoWrapper.js");
load("Block.js");
load("BoolLiteral.js");
load("Break.js");
@@ -63,6 +64,7 @@
load("EPtr.js");
load("EvaluationCommon.js");
load("Evaluator.js");
+load("ExpressionFinder.js");
load("Field.js");
load("ForLoop.js");
load("Func.js");
Added: trunk/Tools/WebGPUShadingLanguageRI/AutoWrapper.js (0 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/AutoWrapper.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/AutoWrapper.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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 AutoWrapper extends Rewriter {
+ visitVariableRef(node)
+ {
+ return node;
+ }
+
+ visitTypeRef(node)
+ {
+ return node;
+ }
+
+ visitConstexprTypeParameter(node)
+ {
+ return VariableRef.wrap(node);
+ }
+
+ visitFuncParameter(node)
+ {
+ return VariableRef.wrap(node);
+ }
+
+ visitVariableDecl(node)
+ {
+ return VariableRef.wrap(node);
+ }
+
+ visitStructType(node)
+ {
+ return TypeRef.wrap(node);
+ }
+
+ visitNativeType(node)
+ {
+ return TypeRef.wrap(node);
+ }
+}
Modified: trunk/Tools/WebGPUShadingLanguageRI/CheckWrapped.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/CheckWrapped.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/CheckWrapped.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -24,10 +24,13 @@
*/
"use strict";
-// FIXME: This doesn't work on Program, so we can't call it from prepare.
-// https://bugs.webkit.org/show_bug.cgi?id=176678
-
-function checkWrapped(node)
+function checkExpressionWrapped(node)
{
node.visit(new WrapChecker(node));
}
+
+function checkProgramWrapped(node)
+{
+ node.visit(new ExpressionFinder(checkExpressionWrapped));
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/Checker.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -101,7 +101,7 @@
return;
if (!node.elementType.instantiatedType.isPrimitive)
- throw new WTypeError(node.origin.originString, "Illegal pointer to non-primitive type: " + node.elementType);
+ throw new WTypeError(node.origin.originString, "Illegal pointer to non-primitive type: " + node.elementType + " (instantiated to " + node.elementType.instantiatedType + ")");
}
visitArrayType(node)
@@ -157,7 +157,7 @@
{
let structType = node.struct.visit(this).unifyNode;
- node.structType = structType;
+ node.structType = TypeRef.wrap(structType);
let underlyingStruct = structType;
Added: trunk/Tools/WebGPUShadingLanguageRI/ExpressionFinder.js (0 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/ExpressionFinder.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/ExpressionFinder.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 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";
+
+// This finds type and value expressions, but skips type and value declarations.
+class ExpressionFinder extends Visitor {
+ constructor(callback)
+ {
+ super();
+ this._callback = callback;
+ }
+
+ visitFunc(node)
+ {
+ this._callback(node.returnType);
+ for (let typeParameter of node.typeParameters)
+ typeParameter.visit(this);
+ for (let parameter of node.parameters)
+ parameter.visit(this);
+ }
+
+ visitFuncParameter(node)
+ {
+ this._callback(node.type);
+ }
+
+ visitConstexprTypeParameter(node)
+ {
+ this._callback(node.type);
+ }
+
+ visitAssignment(node)
+ {
+ this._callback(node);
+ }
+
+ visitCallExpression(node)
+ {
+ this._callback(node);
+ }
+
+ visitReturn(node)
+ {
+ if (node.value)
+ this._callback(node.value);
+ }
+
+ visitWhileLoop(node)
+ {
+ this._callback(node.conditional);
+ node.body.visit(this);
+ }
+
+ visitDoWhileLoop(node)
+ {
+ node.body.visit(this);
+ this._callback(node.conditional);
+ }
+
+ visitIfStatement(node)
+ {
+ this._callback(node.conditional);
+ node.body.visit(this);
+ if (node.elseBody)
+ node.elseBody.visit(this);
+ }
+
+ visitForLoop(node)
+ {
+ // Initialization is a statement, not an _expression_. If it's an assignment or variableDecl, we'll
+ // catch it and redirect to the callback.
+ if (node.initialization)
+ node.initialization.visit(this);
+
+ if (node.condition)
+ this._callback(node.condition);
+ if (node.increment)
+ this._callback(node.increment);
+
+ node.body.visit(this);
+ }
+
+ visitVariableDecl(node)
+ {
+ this._callback(node.type);
+ if (node.initializer)
+ this._callback(node.initializer);
+ }
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/NativeFuncInstance.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/NativeFuncInstance.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/NativeFuncInstance.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -28,6 +28,7 @@
constructor(func, returnType, parameters, isCast)
{
super(func.origin, func.name, returnType, [], parameters, isCast);
+ this._func = func;
}
get func() { return this._func; }
Modified: trunk/Tools/WebGPUShadingLanguageRI/Node.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/Node.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/Node.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -109,9 +109,4 @@
parameters,
parameters.map(type => unificationContext.find(type)));
}
-
- clone()
- {
- return this.visit(new Rewriter());
- }
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Prepare.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/Prepare.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/Prepare.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -33,10 +33,12 @@
resolveTypeDefs(program);
check(program);
checkLiteralTypes(program);
+ checkProgramWrapped(program);
checkReturns(program);
checkUnreachableCode(program);
checkLoops(program);
checkRecursion(program);
+ checkProgramWrapped(program);
inline(program);
return program;
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/StructLayoutBuilder.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/StructLayoutBuilder.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/StructLayoutBuilder.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -31,6 +31,10 @@
this._offset = 0;
}
+ visitReferenceType(node)
+ {
+ }
+
visitStructType(node)
{
if (node.size != null)
@@ -48,6 +52,7 @@
visitField(node)
{
+ super.visitField(node);
node.offset = this._offset;
let size = node.type.size;
if (size == null)
Modified: trunk/Tools/WebGPUShadingLanguageRI/Substitution.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/Substitution.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/Substitution.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -31,11 +31,8 @@
if (parameters.length != argumentList.length)
throw new Error("Parameters and arguments are mismatched");
this._map = new Map();
- for (let i = 0; i < parameters.length; ++i) {
- if (argumentList[i] instanceof Value)
- checkWrapped(argumentList[i]);
+ for (let i = 0; i < parameters.length; ++i)
this._map.set(parameters[i], argumentList[i]);
- }
}
visitTypeRef(node)
@@ -44,12 +41,7 @@
if (replacement) {
if (node.typeArguments.length)
throw new Error("Unexpected type arguments on type variable");
- // When we substitute types, we simply wrap them in a ref. We do this because when we work with
- // types, we often point to types directly.
- // FIXME: What if we end of wrapping something like PtrType(TypeVariable)? Won't that then prevent
- // further substitution?
- // https://bugs.webkit.org/show_bug.cgi?id=176677
- return TypeRef.wrap(replacement);
+ return replacement.visit(new AutoWrapper());
}
let result = super.visitTypeRef(node);
@@ -59,12 +51,8 @@
visitVariableRef(node)
{
let replacement = this._map.get(node.variable);
- if (replacement) {
- // FIXME: What if we end up getting passed a ConstexprTypeParameter? Won't that prevent further
- // substitution?
- // https://bugs.webkit.org/show_bug.cgi?id=176677
- return replacement.clone();
- }
+ if (replacement)
+ return replacement.visit(new AutoWrapper());
return super.visitVariableRef(node);
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-11 22:53:36 UTC (rev 221888)
@@ -13,6 +13,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -39,6 +40,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -1842,6 +1842,141 @@
checkInt(program, callFunction(program, "foo", [], [makeInt(program, 7)]), 7);
}
+function TEST_chainConstexpr()
+{
+ let program = doPrep(`
+ int foo<int a>(int b)
+ {
+ return a + b;
+ }
+ int bar<int a>(int b)
+ {
+ return foo<a>(b);
+ }
+ int baz(int b)
+ {
+ return bar<42>(b);
+ }
+ `);
+ checkInt(program, callFunction(program, "baz", [], [makeInt(program, 58)]), 58 + 42);
+}
+
+function TEST_chainGeneric()
+{
+ let program = doPrep(`
+ T foo<T>(T x)
+ {
+ return x;
+ }
+ T bar<T>(thread T^ ptr)
+ {
+ return ^foo(ptr);
+ }
+ int baz(int x)
+ {
+ return bar(&x);
+ }
+ `);
+ checkInt(program, callFunction(program, "baz", [], [makeInt(program, 37)]), 37);
+}
+
+function TEST_chainStruct()
+{
+ let program = doPrep(`
+ struct Foo<T> {
+ T f;
+ }
+ struct Bar<T> {
+ Foo<thread T^> f;
+ }
+ int foo(thread Bar<int>^ x)
+ {
+ return ^x->f.f;
+ }
+ int bar(int a)
+ {
+ Bar<int> x;
+ x.f.f = &a;
+ return foo(&x);
+ }
+ `);
+ checkInt(program, callFunction(program, "bar", [], [makeInt(program, 4657)]), 4657);
+}
+
+function TEST_chainStructInvalid()
+{
+ checkFail(
+ () => doPrep(`
+ struct Foo<T> {
+ T f;
+ }
+ struct Bar<T> {
+ Foo<device T^> f;
+ }
+ int foo(thread Bar<int>^ x)
+ {
+ return ^x->f.f;
+ }
+ int bar(device int^ a)
+ {
+ Bar<int> x;
+ x.f.f = a;
+ return foo(&x);
+ }
+ `),
+ (e) => e instanceof WTypeError);
+}
+
+function TEST_chainStructDevice()
+{
+ let program = doPrep(`
+ struct Foo<T> {
+ T f;
+ }
+ struct Bar<T:primitive> {
+ Foo<device T^> f;
+ }
+ int foo(thread Bar<int>^ x)
+ {
+ return ^x->f.f;
+ }
+ int bar(device int^ a)
+ {
+ Bar<int> x;
+ x.f.f = a;
+ return foo(&x);
+ }
+ `);
+ let buffer = new EBuffer(1);
+ buffer.set(0, 79201);
+ checkInt(program, callFunction(program, "bar", [], [TypedValue.box(new PtrType(null, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 79201);
+}
+
+function TEST_paramChainStructDevice()
+{
+ let program = doPrep(`
+ struct Foo<T> {
+ T f;
+ }
+ struct Bar<T> {
+ Foo<T> f;
+ }
+ int foo(thread Bar<device int^>^ x)
+ {
+ return ^x->f.f;
+ }
+ int bar(device int^ a)
+ {
+ Bar<device int^> x;
+ x.f.f = a;
+ return foo(&x);
+ }
+ `);
+ let buffer = new EBuffer(1);
+ buffer.set(0, 79201);
+ checkInt(program, callFunction(program, "bar", [], [TypedValue.box(new PtrType(null, "device", program.intrinsics.int32), new EPtr(buffer, 0))]), 79201);
+}
+
let filter = /.*/; // run everything by default
if (this["arguments"]) {
for (let i = 0; i < arguments.length; i++) {
Modified: trunk/Tools/WebGPUShadingLanguageRI/Visitor.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -110,7 +110,7 @@
visitNativeTypeInstance(node)
{
- node.type.visit(node);
+ node.type.visit(this);
for (let typeArgument of node.typeArguments)
typeArgument.visit(this);
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/WrapChecker.js (221887 => 221888)
--- trunk/Tools/WebGPUShadingLanguageRI/WrapChecker.js 2017-09-11 22:51:18 UTC (rev 221887)
+++ trunk/Tools/WebGPUShadingLanguageRI/WrapChecker.js 2017-09-11 22:53:36 UTC (rev 221888)
@@ -41,7 +41,15 @@
_foundUnwrapped(node)
{
- throw new Error("Found unwrapped " + node.constructor.name + " at " + node.origin.originString + ": " + node + "\nWhile visiting " + this._startNode.constructor.name + " at " + this._startNode.origin.originString + ": " + this._startNode);
+ function originString(node)
+ {
+ let origin = node.origin;
+ if (!origin)
+ return "<null origin>";
+ return origin.originString;
+ }
+
+ throw new Error("Found unwrapped " + node.constructor.name + " at " + originString(node) + ": " + node + "\nWhile visiting " + this._startNode.constructor.name + " at " + originString(this._startNode.origin) + ": " + this._startNode);
}
visitConstexprTypeParameter(node)
@@ -68,4 +76,9 @@
{
this._foundUnwrapped(node);
}
+
+ // NOTE: This does not know how to handle NativeTypeInstance, because this is never called on instantiated
+ // code. Once code is instantiated, you cannot instantiate it further.
+
+ // NOTE: This needs to be kept in sync with AutoWrapper.
}