Diff
Modified: trunk/Tools/ChangeLog (235878 => 235879)
--- trunk/Tools/ChangeLog 2018-09-11 01:18:05 UTC (rev 235878)
+++ trunk/Tools/ChangeLog 2018-09-11 01:25:13 UTC (rev 235879)
@@ -1,3 +1,41 @@
+2018-09-10 Thomas Denney <[email protected]>
+
+ [WHLSL] Inlining should be optional
+ https://bugs.webkit.org/show_bug.cgi?id=188641
+
+ Reviewed by Myles C. Maxfield.
+
+ Inlining functions is now optional, and disabled by default. This patch
+ additionally resolves https://bugs.webkit.org/show_bug.cgi?id=189326 as
+ the code for calling functions was completely rewritten.
+
+ * WebGPUShadingLanguageRI/All.js: Add LateCheckAndLayoutBuffers.js
+ * WebGPUShadingLanguageRI/CallFunction.js:
+ (callFunction): Remove dependency on inlining.
+ * WebGPUShadingLanguageRI/Evaluator.js:
+ (Evaluator.prototype._snapshot): Allow null srcPtr in the case of void
+ returns from functions.
+ (Evaluator.prototype._evaluateArguments): Abstract out argument
+ evaluation, ensuring that the order is right-to-left for
+ FunctionLikeBlocks (i.e. inlined functions) and regular calls.
+ (Evaluator.prototype._evaluateFunction): Abstracted out function body
+ evaluation for inlined and non-inlined functions.
+ (Evaluator.prototype.visitFunctionLikeBlock): Ditto.
+ (Evaluator.prototype.visitCallExpression): Ditto.
+ * WebGPUShadingLanguageRI/Inline.js:
+ (_inlineFunction): Moved logic that is needed regardless of inlining
+ into LateCheckAndLayoutBuffers.js
+ (resolveInlinedFunction): Deleted.
+ * WebGPUShadingLanguageRI/LateCheckAndLayoutBuffers.js: Moved logic for
+ late checking.
+ * WebGPUShadingLanguageRI/Prepare.js: Make inlining optional and off by
+ default.
+ * WebGPUShadingLanguageRI/SPIRV.html: Update include.
+ * WebGPUShadingLanguageRI/Test.html: Ditto.
+ * WebGPUShadingLanguageRI/Test.js: Right-to-left argument evaluation,
+ and inlining tests.
+ * WebGPUShadingLanguageRI/index.html: Update include.
+
2018-09-10 Wenson Hsieh <[email protected]>
[iOS] Unable to change the value of select elements while preserving focus state
Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (235878 => 235879)
--- trunk/Tools/WebGPUShadingLanguageRI/All.js 2018-09-11 01:18:05 UTC (rev 235878)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js 2018-09-11 01:25:13 UTC (rev 235879)
@@ -102,6 +102,7 @@
load("IntLiteral.js");
load("IntLiteralType.js");
load("Intrinsics.js");
+load("LateCheckAndLayoutBuffers.js");
load("LateChecker.js");
load("Lexer.js");
load("LexerToken.js");
Modified: trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js (235878 => 235879)
--- trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js 2018-09-11 01:18:05 UTC (rev 235878)
+++ trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js 2018-09-11 01:25:13 UTC (rev 235879)
@@ -28,12 +28,11 @@
function callFunction(program, name, argumentList)
{
let argumentTypes = argumentList.map(argument => argument.type);
- let funcOrFailures = resolveInlinedFunction(program, name, argumentTypes, true);
- if (!(funcOrFailures instanceof Func)) {
- let failures = funcOrFailures;
- throw new WTypeError("<callFunction>", "Cannot resolve function call " + name + "(" + argumentList + ")" + (failures.length ? "; tried:\n" + failures.join("\n") : ""));
- }
- let func = funcOrFailures;
+ let overload = program.globalNameContext.resolveFuncOverload(name, argumentTypes, null, true);
+ if (!overload.func)
+ throw new WTypeError("<callFunction>", "Cannot resolve function call " + name + "(" + argumentList + ")" + (overload.failures.length ? "; tried:\n" + overload.failures.join("\n") : ""));
+
+ const func = overload.func;
for (let i = 0; i < func.parameters.length; ++i) {
let type = argumentTypes[i];
type.visit(new StructLayoutBuilder());
Modified: trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js (235878 => 235879)
--- trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2018-09-11 01:18:05 UTC (rev 235878)
+++ trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2018-09-11 01:25:13 UTC (rev 235879)
@@ -37,6 +37,8 @@
// possible for a pointer returned from a visit method in rvalue context to live across any effects.
_snapshot(type, dstPtr, srcPtr)
{
+ if (!srcPtr)
+ return null;
let size = type.size;
if (size == null)
throw new Error("Cannot get size of type: " + type + " (size = " + size + ", constructor = " + type.constructor.name + ")");
@@ -71,17 +73,35 @@
throw e;
}
}
-
- visitFunctionLikeBlock(node)
+
+ _evaluateArguments(argumentList, parameterList)
{
- for (let i = 0; i < node.argumentList.length; ++i) {
- node.parameters[i].ePtr.copyFrom(
- node.argumentList[i].visit(this),
- node.parameters[i].type.size);
+ const callArguments = [];
+ for (let i = argumentList.length; i--;) {
+ const argument = argumentList[i];
+ const type = parameterList[i].type;
+ if (!type || !argument)
+ throw new Error("Cannot get type or argument; i = " + i + ", argument = " + argument + ", type = " + type);
+ let argumentValue = argument.visit(this);
+ if (!argumentValue)
+ throw new Error("Null argument value, i = " + i + ", node = " + node);
+ callArguments.unshift(EBuffer.allowAllocation(() => this._snapshot(type, null, argumentValue)));
}
- let result = this._runBody(node.returnType, node.returnEPtr, node.body);
- return result;
+ return callArguments;
}
+
+ _evaluateFunction(node, argumentList, parameterList, funcBody, returnType, returnEPtr)
+ {
+ const argumentValues = this._evaluateArguments(argumentList, parameterList);
+ for (let i = 0; i < node.argumentList.length; ++i)
+ parameterList[i].ePtr.copyFrom(argumentValues[i], parameterList[i].type.size);
+ return EBuffer.allowAllocation(() => this._runBody(returnType, returnEPtr, funcBody));
+ }
+
+ visitFunctionLikeBlock(node)
+ {
+ return this._evaluateFunction(node, node.argumentList, node.parameters, node.body, node.returnType, node.returnEPtr);
+ }
visitReturn(node)
{
@@ -310,21 +330,11 @@
visitCallExpression(node)
{
- // We evaluate inlined ASTs, so this can only be a native call.
- let callArguments = [];
- for (let i = 0; i < node.argumentList.length; ++i) {
- let argument = node.argumentList[i];
- let type = node.func.parameterTypes[i];
- if (!type || !argument)
- throw new Error("Cannot get type or argument; i = " + i + ", argument = " + argument + ", type = " + type + "; in " + node);
- let argumentValue = argument.visit(this);
- if (!argumentValue)
- throw new Error("Null argument value, i = " + i + ", node = " + node);
- callArguments.push(EBuffer.allowAllocation(() => this._snapshot(type, null, argumentValue)));
- }
- let result = EBuffer.allowAllocation(() => node.func.implementation(callArguments, node));
- result = this._snapshot(node.func.returnType, node.resultEPtr, result);
- return result;
+ if (node.func instanceof NativeFunc) {
+ const callArguments = this._evaluateArguments(node.argumentList, node.func.parameters);
+ return EBuffer.allowAllocation(() => this._snapshot(node.func.returnType, node.resultEPtr, node.func.implementation(callArguments, node)));
+ } else
+ return this._evaluateFunction(node, node.argumentList, node.func.parameters, node.func.body, node.func.returnType, node.resultEPtr);
}
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Inline.js (235878 => 235879)
--- trunk/Tools/WebGPUShadingLanguageRI/Inline.js 2018-09-11 01:18:05 UTC (rev 235878)
+++ trunk/Tools/WebGPUShadingLanguageRI/Inline.js 2018-09-11 01:25:13 UTC (rev 235879)
@@ -36,26 +36,6 @@
{
if (func.inlined || func.isNative)
return;
-
- func.visit(new LateChecker());
-
- // This is the precise time when we can build EBuffers in order to get them to be uniqued by
- // type instantiation but nothing else.
- func.visit(new StructLayoutBuilder());
- func.visit(new EBufferBuilder(program));
-
func.rewrite(new Inliner(program, func, visiting));
-
func.inlined = true;
}
-
-function resolveInlinedFunction(program, name, argumentTypes, allowEntryPoint = false)
-{
- let overload = program.globalNameContext.resolveFuncOverload(name, argumentTypes, undefined, allowEntryPoint);
- if (!overload.func)
- return overload.failures;
-
- let func = overload.func;
- _inlineFunction(program, func, new VisitingSet(func));
- return func;
-}
Copied: trunk/Tools/WebGPUShadingLanguageRI/LateCheckAndLayoutBuffers.js (from rev 235878, trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js) (0 => 235879)
--- trunk/Tools/WebGPUShadingLanguageRI/LateCheckAndLayoutBuffers.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/LateCheckAndLayoutBuffers.js 2018-09-11 01:25:13 UTC (rev 235879)
@@ -0,0 +1,37 @@
+/*
+ * 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 lateCheckAndLayoutBuffers(program)
+{
+ for (let funcList of program.functions.values()) {
+ for (let func of funcList) {
+ if (func.isNative)
+ continue;
+ func.visit(new LateChecker());
+ func.visit(new EBufferBuilder());
+ }
+ }
+}
\ No newline at end of file
Modified: trunk/Tools/WebGPUShadingLanguageRI/Prepare.js (235878 => 235879)
--- trunk/Tools/WebGPUShadingLanguageRI/Prepare.js 2018-09-11 01:18:05 UTC (rev 235878)
+++ trunk/Tools/WebGPUShadingLanguageRI/Prepare.js 2018-09-11 01:25:13 UTC (rev 235879)
@@ -26,7 +26,7 @@
let prepare = (() => {
let standardProgram;
- return function(origin, lineNumberOffset, text) {
+ return function(origin, lineNumberOffset, text, shouldInline = false) {
if (!standardProgram) {
standardProgram = new Program();
let firstLineOfStandardLibrary = 28; // See StandardLibrary.js.
@@ -68,8 +68,9 @@
checkTypesWithArguments(program);
findHighZombies(program);
program.visit(new StructLayoutBuilder());
- inline(program);
-
+ lateCheckAndLayoutBuffers(program);
+ if (shouldInline)
+ inline(program);
return program;
};
})();
Modified: trunk/Tools/WebGPUShadingLanguageRI/SPIRV.html (235878 => 235879)
--- trunk/Tools/WebGPUShadingLanguageRI/SPIRV.html 2018-09-11 01:18:05 UTC (rev 235878)
+++ trunk/Tools/WebGPUShadingLanguageRI/SPIRV.html 2018-09-11 01:25:13 UTC (rev 235879)
@@ -85,6 +85,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (235878 => 235879)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.html 2018-09-11 01:18:05 UTC (rev 235878)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html 2018-09-11 01:25:13 UTC (rev 235879)
@@ -80,6 +80,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (235878 => 235879)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.js 2018-09-11 01:18:05 UTC (rev 235878)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js 2018-09-11 01:25:13 UTC (rev 235879)
@@ -7848,6 +7848,82 @@
checkInt(program, callFunction(program, "foo", []), 12);
};
+tests.evaluationOrderForArguments = () => {
+ const program = doPrep(`
+ test int foo() { return *bar(10) + *bar(20); }
+
+ thread int* bar(int value)
+ {
+ int x = value;
+ return &x;
+ }
+
+ test int baz() { return plus(bar(10), bar(20)); }
+
+ int plus(thread int* x, thread int* y)
+ {
+ return *x + *y;
+ }
+ `);
+ checkInt(program, callFunction(program, "foo", []), 30);
+ checkInt(program, callFunction(program, "baz", []), 20);
+}
+
+tests.cannotCallAnotherEntryPoint = () => {
+ checkFail(() => doPrep(`
+ struct Foo { int x; }
+ vertex Foo foo() { return bar(); }
+ vertex Foo bar() { return Foo(); }
+ `), e => e instanceof WTypeError && e.message.indexOf("it cannot be called from within an existing shader") !== -1);
+}
+
+tests.inliningDoesNotAffectNestedCalls = () => {
+ const program = prepare("/internal/test", 0, `
+ test int foo()
+ {
+ return plus(bar(), baz());
+ }
+
+ int plus(int a, int b)
+ {
+ return a + b;
+ }
+
+ int bar()
+ {
+ return 17;
+ }
+
+ int baz()
+ {
+ return 3;
+ }
+ `, true);
+ checkInt(program, callFunction(program, "foo", []), 20)
+}
+
+tests.inliningDoesntProduceAliasingIssues = () => {
+ const program = prepare("/internal/test", 0, `
+ test int foo()
+ {
+ return bar(2);
+ }
+
+ int bar(int x)
+ {
+ int y = x * x;
+ return baz(y);
+ }
+
+ int baz(int x)
+ {
+ int y = 4 * x;
+ return x + y;
+ }
+ `, true);
+ checkInt(program, callFunction(program, "foo", []), 20);
+}
+
okToTest = true;
let testFilter = /.*/; // run everything by default
Modified: trunk/Tools/WebGPUShadingLanguageRI/index.html (235878 => 235879)
--- trunk/Tools/WebGPUShadingLanguageRI/index.html 2018-09-11 01:18:05 UTC (rev 235878)
+++ trunk/Tools/WebGPUShadingLanguageRI/index.html 2018-09-11 01:25:13 UTC (rev 235879)
@@ -79,6 +79,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""