Title: [235879] trunk/Tools
Revision
235879
Author
[email protected]
Date
2018-09-10 18:25:13 -0700 (Mon, 10 Sep 2018)

Log Message

[WHLSL] Inlining should be optional
https://bugs.webkit.org/show_bug.cgi?id=188641

Patch by Thomas Denney <[email protected]> on 2018-09-10
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.

Modified Paths

Added Paths

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=""
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to