Title: [236361] trunk/Tools
Revision
236361
Author
[email protected]
Date
2018-09-21 14:46:02 -0700 (Fri, 21 Sep 2018)

Log Message

[WHLSL] Local variables should be statically allocated
https://bugs.webkit.org/show_bug.cgi?id=188402

Patch by Thomas Denney <[email protected]> on 2018-09-21
Reviewed by Myles C. Maxfield.

An additional preparation stage is now performed so that all local
variables and function parameters are allocated in a single struct at
entry points. A pointer to this struct is then passed for function
calls.

* WebGPUShadingLanguageRI/All.js: Update dependencies.
* WebGPUShadingLanguageRI/AllocateAtEntryPoints.js: Added new stage.
* WebGPUShadingLanguageRI/CallExpression.js:
(CallExpression.prototype.set argumentList): Add setter because
allocateAtEntryPoints needs to change this.
* WebGPUShadingLanguageRI/EBufferBuilder.js: Remove a redundant
constructor that wasn't used anywhere.
* WebGPUShadingLanguageRI/Func.js:
(Func.prototype.set parameters): Add setter.
* WebGPUShadingLanguageRI/FuncDef.js:
(FuncDef.prototype.set body): Ditto.
* WebGPUShadingLanguageRI/Prepare.js:
(let.prepare): Add call to allocateAtEntryPoints. This call cannot
happen any earlier because it depends on having types for call
arguments.
* WebGPUShadingLanguageRI/Rewriter.js:
(Rewriter.prototype.visitReturn): Resolve issue where the return
statement's function wasn't copied. A null check is required as the
Rewriter might be used before this property is set.
* WebGPUShadingLanguageRI/SPIRV.html: Update dependencies.
* WebGPUShadingLanguageRI/SynthesizeStructAccessors.js: Abstracted logic
into a separate function so that allocateAtEntryPoints can create the
accessors for the struct type it introduces.
* WebGPUShadingLanguageRI/Test.html: Update dependencies.
* WebGPUShadingLanguageRI/Test.js: Add new tests to verify the static
allocation transform works safely.
* WebGPUShadingLanguageRI/index.html: Update dependencies.

Modified Paths

Added Paths

Diff

Modified: trunk/Tools/ChangeLog (236360 => 236361)


--- trunk/Tools/ChangeLog	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/ChangeLog	2018-09-21 21:46:02 UTC (rev 236361)
@@ -1,3 +1,43 @@
+2018-09-21  Thomas Denney  <[email protected]>
+
+        [WHLSL] Local variables should be statically allocated
+        https://bugs.webkit.org/show_bug.cgi?id=188402
+
+        Reviewed by Myles C. Maxfield.
+
+        An additional preparation stage is now performed so that all local
+        variables and function parameters are allocated in a single struct at
+        entry points. A pointer to this struct is then passed for function
+        calls.
+
+        * WebGPUShadingLanguageRI/All.js: Update dependencies.
+        * WebGPUShadingLanguageRI/AllocateAtEntryPoints.js: Added new stage.
+        * WebGPUShadingLanguageRI/CallExpression.js:
+        (CallExpression.prototype.set argumentList): Add setter because
+        allocateAtEntryPoints needs to change this.
+        * WebGPUShadingLanguageRI/EBufferBuilder.js: Remove a redundant
+        constructor that wasn't used anywhere.
+        * WebGPUShadingLanguageRI/Func.js:
+        (Func.prototype.set parameters): Add setter.
+        * WebGPUShadingLanguageRI/FuncDef.js:
+        (FuncDef.prototype.set body): Ditto.
+        * WebGPUShadingLanguageRI/Prepare.js:
+        (let.prepare): Add call to allocateAtEntryPoints. This call cannot
+        happen any earlier because it depends on having types for call
+        arguments.
+        * WebGPUShadingLanguageRI/Rewriter.js:
+        (Rewriter.prototype.visitReturn): Resolve issue where the return
+        statement's function wasn't copied. A null check is required as the
+        Rewriter might be used before this property is set.
+        * WebGPUShadingLanguageRI/SPIRV.html: Update dependencies.
+        * WebGPUShadingLanguageRI/SynthesizeStructAccessors.js: Abstracted logic
+        into a separate function so that allocateAtEntryPoints can create the
+        accessors for the struct type it introduces.
+        * WebGPUShadingLanguageRI/Test.html: Update dependencies.
+        * WebGPUShadingLanguageRI/Test.js: Add new tests to verify the static
+        allocation transform works safely.
+        * WebGPUShadingLanguageRI/index.html: Update dependencies.
+
 2018-09-21  Jonathan Bedard  <[email protected]>
 
         Bring up queues for iOS 12 (Build fix)

Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/All.js	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js	2018-09-21 21:46:02 UTC (rev 236361)
@@ -37,6 +37,7 @@
 load("NativeType.js");
 
 load("AddressSpace.js");
+load("AllocateAtEntryPoints.js");
 load("AnonymousVariable.js");
 load("ArrayRefType.js");
 load("ArrayType.js");

Added: trunk/Tools/WebGPUShadingLanguageRI/AllocateAtEntryPoints.js (0 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/AllocateAtEntryPoints.js	                        (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/AllocateAtEntryPoints.js	2018-09-21 21:46:02 UTC (rev 236361)
@@ -0,0 +1,255 @@
+/*
+ * 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 gatherEntryPoints(program)
+{
+    const entryPoints = new Set();
+    for (let [name, funcDefs] of program.functions) {
+        for (let funcDef of funcDefs) {
+            if (funcDef.isEntryPoint)
+                entryPoints.add(funcDef);
+        }
+    }
+    return entryPoints;
+}
+
+function gatherCallees(funcDefs)
+{
+    const calleeSet = new Set();
+    class FindFunctionsThatAreCalled extends Visitor
+    {
+        visitCallExpression(node)
+        {
+            super.visitCallExpression(node);
+            if (node.func instanceof FuncDef && !calleeSet.has(node.func)) {
+                calleeSet.add(node.func);
+                node.func.visit(this);
+            }
+        }
+    }
+    const visitor = new FindFunctionsThatAreCalled();
+    for (let funcDef of funcDefs)
+        funcDef.visit(visitor);
+    return calleeSet;
+}
+
+function gatherVariablesAndFunctionParameters(funcDefs)
+{
+    const varsAndParams = new Set();
+    class VarAndParamVisitor extends Visitor {
+
+        constructor(isEntryPoint)
+        {
+            super();
+            this._isEntryPoint = isEntryPoint;
+        }
+
+        visitFuncParameter(node)
+        {
+            if (!this._isEntryPoint)
+                varsAndParams.add(node);
+        }
+
+        visitVariableDecl(node)
+        {
+            varsAndParams.add(node);
+        }
+    }
+    for (let func of funcDefs)
+        func.visit(new VarAndParamVisitor(func.isEntryPoint));
+    return varsAndParams;
+}
+
+function createGlobalStructTypeAndVarToFieldMap(origin, allVariablesAndFunctionParameters, functionsThatAreCalledByEntryPoints)
+{
+    const globalStructType = new StructType(origin, null);
+    let counter = 0;
+    const varToFieldMap = new Map();
+
+    for (let varOrParam of allVariablesAndFunctionParameters) {
+        const fieldName = `field${counter++}_${varOrParam.name}`;
+        globalStructType.add(new Field(varOrParam.origin, fieldName, varOrParam.type));
+        varToFieldMap.set(varOrParam, fieldName);
+    }
+
+    for (let func of functionsThatAreCalledByEntryPoints) {
+        if (func.returnType.name !== "void") {
+            const fieldName = `field${counter++}_return_${func.name}`;
+            globalStructType.add(new Field(func.origin, fieldName, func.returnType));
+            func.returnFieldName = fieldName;
+        }
+    }
+
+    return [ globalStructType, varToFieldMap ];
+}
+
+function allocateAtEntryPoints(program)
+{
+    const entryPoints = gatherEntryPoints(program);
+    const allCallees = gatherCallees(entryPoints);
+    const allExecutedFunctions = new Set([...entryPoints, ...allCallees]);
+    const allVariablesAndFunctionParameters = gatherVariablesAndFunctionParameters(allExecutedFunctions);
+
+    if (!allVariablesAndFunctionParameters.size)
+        return;
+
+    const anyEntryPoint = entryPoints.values().next().value;
+    const [ globalStructType, varToFieldMap ] = createGlobalStructTypeAndVarToFieldMap(anyEntryPoint.origin, allVariablesAndFunctionParameters, allCallees);
+    program.add(globalStructType);
+    // All other struct accessors will have been synthesized at this point (they have to be synthesized earlier for call resolution).
+    synthesizeStructAccessorsForStructType(program, globalStructType);
+
+    const globalStructTypeRef = TypeRef.wrap(globalStructType);
+    const ptrToGlobalStructType = new PtrType(anyEntryPoint.origin, "thread", globalStructTypeRef);
+    const ptrToGlobalStructTypeRef = TypeRef.wrap(ptrToGlobalStructType);
+
+    const funcNewParameterMapping = new Map();
+    function updateFunction(func)
+    {
+        class UpdateFunctions extends Rewriter {
+            constructor()
+            {
+                super();
+                if (func.isEntryPoint)
+                    this._addVariableDeclaration();
+                else
+                    this._reconfigureParameters();
+                func.body = func._body.visit(this);
+            }
+
+            _addVariableDeclaration()
+            {
+                this._variableDecl = new VariableDecl(func.origin, null, globalStructTypeRef, null);
+                this.makeGlobalStructVariableRef = () => new MakePtrExpression(func.origin, VariableRef.wrap(this._variableDecl));
+                func.body.statements.unshift(this._variableDecl);
+            }
+
+            _reconfigureParameters()
+            {
+                const funcParam = new FuncParameter(func.origin, null, ptrToGlobalStructTypeRef);
+                this.makeGlobalStructVariableRef = () =>  VariableRef.wrap(funcParam);
+                funcNewParameterMapping.set(func, [ funcParam ]);
+            }
+
+            _callExpressionForFieldName(node, fieldName)
+            {
+                if (!fieldName)
+                    throw new Error("Field name was null");
+                const functionName = `operator&.${fieldName}`;
+                const possibleAndOverloads = program.globalNameContext.get(Func, functionName);
+                const callExpressionResolution = CallExpression.resolve(node.origin, possibleAndOverloads, functionName, [ this.makeGlobalStructVariableRef() ], [ ptrToGlobalStructTypeRef ]);
+                return callExpressionResolution.call;
+            }
+
+            _dereferencedCallExpressionForFieldName(node, resultType, fieldName)
+            {
+                const derefExpr = new DereferenceExpression(node.origin, this._callExpressionForFieldName(node, fieldName), node.type, "thread");
+                derefExpr.type = resultType;
+                return derefExpr;
+            }
+
+            visitVariableRef(node)
+            {
+                if (!varToFieldMap.has(node.variable))
+                    return super.visitVariableRef(node);
+                return this._dereferencedCallExpressionForFieldName(node, node.variable.type, varToFieldMap.get(node.variable));
+            }
+
+            visitVariableDecl(node)
+            {
+                if (node == this._variableDecl)
+                    return node;
+                else if (node.initializer) {
+                    if (!node.type)
+                        throw new Error(`${node} doesn't have a type`);
+                    return new Assignment(node.origin, this._dereferencedCallExpressionForFieldName(node, node.type, varToFieldMap.get(node)), node.initializer.visit(this), node.type);
+                }
+                return new Block(node.origin);
+            }
+
+            visitCallExpression(node)
+            {
+                node = super.visitCallExpression(node);
+                if (node.func instanceof FuncDef) {
+                    let exprs = [];
+                    const anonymousVariableAssignments = [];
+                    for (let i = node.argumentList.length; i--;) {
+                        const type = node.func.parameters[i].type;
+                        if (!type)
+                            throw new Error(`${node.func.parameters[i]} has no type`);
+                        const anonymousVariable = new AnonymousVariable(node.origin, type);
+                        exprs.push(anonymousVariable);
+                        exprs.push(new Assignment(node.origin, VariableRef.wrap(anonymousVariable), node.argumentList[i], type));
+                        anonymousVariableAssignments.push(new Assignment(node.origin, this._dereferencedCallExpressionForFieldName(node.func.parameters[i], node.func.parameters[i].type, varToFieldMap.get(node.func.parameters[i])), VariableRef.wrap(anonymousVariable), type));
+                    }
+                    exprs = exprs.concat(anonymousVariableAssignments);
+                    exprs.push(node);
+
+                    if (node.func.returnType.name !== "void")
+                        exprs.push(this._dereferencedCallExpressionForFieldName(node.func, node.func.returnType, node.func.returnFieldName));
+
+                    node.argumentList = [ this.makeGlobalStructVariableRef() ];
+                    return new CommaExpression(node.origin, exprs);
+                }
+
+                return node;
+            }
+
+            visitReturn(node)
+            {
+                node = super.visitReturn(node);
+                if (!func.isEntryPoint && node.value) {
+                    return new CommaExpression(node.origin, [
+                        new Assignment(node.origin, this._dereferencedCallExpressionForFieldName(func, func.returnType, func.returnFieldName), node.value, func.returnType),
+                        new Return(node.origin) ]);
+                } else
+                    return node;
+            }
+        }
+        func.visit(new UpdateFunctions());
+    }
+
+    for (let funcDef of allExecutedFunctions)
+        updateFunction(funcDef);
+
+    for (let [func, newParameters] of funcNewParameterMapping)
+        func.parameters = newParameters;
+
+    for (let func of allCallees)
+        func._returnType = TypeRef.wrap(program.types.get("void"));
+
+    class UpdateCallExpressionReturnTypes extends Visitor {
+        visitCallExpression(node)
+        {
+            super.visitCallExpression(node);
+            if (node.func instanceof FuncDef)
+                node._returnType = node.resultType = TypeRef.wrap(program.types.get("void"));
+        }
+    }
+    const updateCallExpressionVisitor = new UpdateCallExpressionReturnTypes();
+    for (let func of allExecutedFunctions)
+        func.visit(updateCallExpressionVisitor);
+}

Modified: trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js	2018-09-21 21:46:02 UTC (rev 236361)
@@ -36,7 +36,14 @@
     }
     
     get name() { return this._name; }
+
     get argumentList() { return this._argumentList; }
+
+    set argumentList(newValue)
+    {
+        this._argumentList = newValue;
+    }
+
     get isCast() { return this._isCast; }
     get returnType() { return this._returnType; }
     

Modified: trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js	2018-09-21 21:46:02 UTC (rev 236361)
@@ -25,12 +25,6 @@
 "use strict";
 
 class EBufferBuilder extends Visitor {
-    constructor(program)
-    {
-        super();
-        this._program = program;
-    }
-    
     _createEPtr(type)
     {
         if (type.size == null)

Modified: trunk/Tools/WebGPUShadingLanguageRI/Func.js (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/Func.js	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/Func.js	2018-09-21 21:46:02 UTC (rev 236361)
@@ -54,6 +54,11 @@
     get isEntryPoint() { return this.shaderType != null; }
     get returnTypeForOverloadResolution() { return this.isCast ? this.returnType : null; }
     
+    set parameters(newValue)
+    {
+        this._parameters = newValue;
+    }
+
     get kind() { return Func; }
     
     toDeclString()

Modified: trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/FuncDef.js	2018-09-21 21:46:02 UTC (rev 236361)
@@ -33,7 +33,12 @@
     }
 
     get body() { return this._body; }
-    
+
+    set body(newBody)
+    {
+        this._body = newBody;
+    }
+
     rewrite(rewriter)
     {
         this._returnType = this._returnType.visit(rewriter);

Modified: trunk/Tools/WebGPUShadingLanguageRI/Prepare.js (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/Prepare.js	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/Prepare.js	2018-09-21 21:46:02 UTC (rev 236361)
@@ -53,7 +53,7 @@
         resolveNamesInFunctions(program, nameResolver);
         resolveTypeDefsInFunctions(program);
         checkTypesWithArguments(program);
-        
+
         check(program);
         checkLiteralTypes(program);
         resolveProperties(program);
@@ -67,6 +67,7 @@
         checkProgramWrapped(program);
         checkTypesWithArguments(program);
         findHighZombies(program);
+        allocateAtEntryPoints(program);
         program.visit(new StructLayoutBuilder());
         lateCheckAndLayoutBuffers(program);
         if (shouldInline)

Modified: trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js	2018-09-21 21:46:02 UTC (rev 236361)
@@ -233,7 +233,10 @@
     
     visitReturn(node)
     {
-        return new Return(node.origin, Node.visit(node.value, this));
+        const returnStatement = new Return(node.origin, Node.visit(node.value, this));
+        if (node.func)
+            returnStatement.func = node.func;
+        return returnStatement;
     }
     
     visitContinue(node)

Modified: trunk/Tools/WebGPUShadingLanguageRI/SPIRV.html (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/SPIRV.html	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/SPIRV.html	2018-09-21 21:46:02 UTC (rev 236361)
@@ -20,6 +20,7 @@
     <script src=""
 
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""

Modified: trunk/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/SynthesizeStructAccessors.js	2018-09-21 21:46:02 UTC (rev 236361)
@@ -20,109 +20,98 @@
  * 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. 
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 "use strict";
 
-function synthesizeStructAccessors(program)
+function synthesizeStructAccessorsForStructType(program, type)
 {
-    for (let type of program.types.values()) {
-        if (!(type instanceof StructType))
-            continue;
-        
-        for (let field of type.fields) {
-            function setupImplementationData(nativeFunc, implementation)
-            {
-                nativeFunc.visitImplementationData = (implementationData, visitor) => {
-                    // Visiting the type first ensures that the struct layout builder figures out the field's
-                    // offset.
-                    implementationData.type.visit(visitor);
-                };
+    for (let field of type.fields) {
+        function setupImplementationData(nativeFunc, implementation)
+        {
+            nativeFunc.visitImplementationData = (implementationData, visitor) => {
+                // Visiting the type first ensures that the struct layout builder figures out the field's
+                // offset.
+                implementationData.type.visit(visitor);
+            };
 
-                nativeFunc.visitImplementationData = (implementationData, visitor) => {
-                    // Visiting the type first ensures that the struct layout builder figures out the field's
-                    // offset.
-                    implementationData.type.visit(visitor);
-                };
+            nativeFunc.implementation = (argumentList, node) => {
+                return implementation(argumentList, field.offset, type.size, field.type.size);
+            };
 
-                nativeFunc.implementation = (argumentList, node) => {
-                    return implementation(argumentList, field.offset, type.size, field.type.size);
-                };
+            nativeFunc.implementationData = {
+                structType: type,
+                name: field.name,
+                type: field.type,
+                offset: field.offset,
+                size: field.type.size
+            };
+        }
 
-                nativeFunc.implementationData = {
-                    structType: type,
-                    name: field.name,
-                    type: field.type,
-                    offset: field.offset,
-                    size: field.type.size
-                };
-            }
-            
-            function createFieldType()
-            {
-                return field.type.visit(new Rewriter());
-            }
-            
-            function createTypeRef()
-            {
-                return TypeRef.wrap(type);
-            }
-            
-            let isCast = false;
-            let shaderType;
-            let nativeFunc;
+        let isCast = false;
+        let shaderType;
+        let nativeFunc;
 
-            // The getter: operator.field
+        // The getter: operator.field
+        nativeFunc = new NativeFunc(
+            field.origin, "operator." + field.name, field.type,
+            [new FuncParameter(field.origin, null, TypeRef.wrap(type))], isCast, shaderType);
+        setupImplementationData(nativeFunc, ([base], offset, structSize, fieldSize) => {
+            let result = new EPtr(new EBuffer(fieldSize), 0);
+            result.copyFrom(base.plus(offset), fieldSize);
+            return result;
+        });
+        program.add(nativeFunc);
+
+        // The setter: operator.field=
+        nativeFunc = new NativeFunc(
+            field.origin, "operator." + field.name + "=", TypeRef.wrap(type),
+            [
+                new FuncParameter(field.origin, null, TypeRef.wrap(type)),
+                new FuncParameter(field.origin, null, field.type)
+            ],
+            isCast, shaderType);
+        setupImplementationData(nativeFunc, ([base, value], offset, structSize, fieldSize) => {
+            let result = new EPtr(new EBuffer(structSize), 0);
+            result.copyFrom(base, structSize);
+            result.plus(offset).copyFrom(value, fieldSize);
+            return result;
+        });
+        program.add(nativeFunc);
+
+        // The ander: operator&.field
+        function setupAnder(addressSpace)
+        {
             nativeFunc = new NativeFunc(
-                field.origin, "operator." + field.name, createFieldType(),
-                [new FuncParameter(field.origin, null, createTypeRef())], isCast, shaderType);
-            setupImplementationData(nativeFunc, ([base], offset, structSize, fieldSize) => {
-                let result = new EPtr(new EBuffer(fieldSize), 0);
-                result.copyFrom(base.plus(offset), fieldSize);
-                return result;
-            });
-            program.add(nativeFunc);
-            
-            // The setter: operator.field=
-            nativeFunc = new NativeFunc(
-                field.origin, "operator." + field.name + "=", createTypeRef(),
+                field.origin, "operator&." + field.name, new PtrType(field.origin, addressSpace, field.type),
                 [
-                    new FuncParameter(field.origin, null, createTypeRef()),
-                    new FuncParameter(field.origin, null, createFieldType())
+                    new FuncParameter(
+                        field.origin, null,
+                        new PtrType(field.origin, addressSpace, TypeRef.wrap(type)))
                 ],
                 isCast, shaderType);
-            setupImplementationData(nativeFunc, ([base, value], offset, structSize, fieldSize) => {
-                let result = new EPtr(new EBuffer(structSize), 0);
-                result.copyFrom(base, structSize);
-                result.plus(offset).copyFrom(value, fieldSize);
-                return result;
+            setupImplementationData(nativeFunc, ([base], offset, structSize, fieldSize) => {
+                base = base.loadValue();
+                if (!base)
+                    throw new WTrapError(field.origin.originString, "Null dereference");
+                return EPtr.box(base.plus(offset));
             });
             program.add(nativeFunc);
-            
-            // The ander: operator&.field
-            function setupAnder(addressSpace)
-            {
-                nativeFunc = new NativeFunc(
-                    field.origin, "operator&." + field.name, new PtrType(field.origin, addressSpace, createFieldType()),
-                    [
-                        new FuncParameter(
-                            field.origin, null,
-                            new PtrType(field.origin, addressSpace, createTypeRef()))
-                    ],
-                    isCast, shaderType);
-                setupImplementationData(nativeFunc, ([base], offset, structSize, fieldSize) => {
-                    base = base.loadValue();
-                    if (!base)
-                        throw new WTrapError(node.origin.originString, "Null dereference");
-                    return EPtr.box(base.plus(offset));
-                });
-                program.add(nativeFunc);
-            }
-            
-            setupAnder("thread");
-            setupAnder("threadgroup");
-            setupAnder("device");
-            setupAnder("constant");
         }
+
+        setupAnder("thread");
+        setupAnder("threadgroup");
+        setupAnder("device");
+        setupAnder("constant");
     }
 }
+
+function synthesizeStructAccessors(program)
+{
+    for (let type of program.types.values()) {
+        if (!(type instanceof StructType))
+            continue;
+
+        synthesizeStructAccessorsForStructType(program, type);
+    }
+}

Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/Test.html	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html	2018-09-21 21:46:02 UTC (rev 236361)
@@ -14,6 +14,7 @@
 <script src=""
 
 <script src=""
+<script src=""
 <script src=""
 <script src=""
 <script src=""

Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/Test.js	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js	2018-09-21 21:46:02 UTC (rev 236361)
@@ -8081,6 +8081,152 @@
     checkInt(program, callFunction(program, "foo", []), 20);
 }
 
+tests.returnReferenceToParameter = () => {
+    let program = doPrep(`
+        test int foo(bool condition)
+        {
+            return *bar(condition, 1, 2);
+        }
+
+        thread int* bar(bool condition, int a, int b)
+        {
+            return condition ? &a : &b;
+        }
+    `);
+
+    checkInt(program, callFunction(program, "foo", [ makeBool(program, true) ]), 1);
+    checkInt(program, callFunction(program, "foo", [ makeBool(program, false) ]), 2);
+}
+
+tests.returnReferenceToParameterWithDifferentFunctions = () => {
+    let program = doPrep(`
+        test int foo()
+        {
+            return *bar(10) + *baz(20);
+        }
+
+        thread int* bar(int x)
+        {
+            return &x;
+        }
+
+        thread int* baz(int y)
+        {
+            return &y;
+        }
+    `);
+
+    checkInt(program, callFunction(program, "foo", []), 30);
+}
+
+tests.returnReferenceToSameParameter = () => {
+    let program = doPrep(`
+        test int foo()
+        {
+            return plus(bar(5), bar(7));
+        }
+
+        int plus(thread int* x, thread int* y)
+        {
+            return *x + *y;
+        }
+
+        thread int* bar(int x)
+        {
+            return &x;
+        }
+    `);
+
+    checkInt(program, callFunction(program, "foo", []), 10);
+}
+
+tests.returnReferenceToLocalVariable = () => {
+    let program = doPrep(`
+        test int foo()
+        {
+            return *bar();
+        }
+
+        thread int* bar()
+        {
+            int a = 42;
+            return &a;
+        }
+    `);
+
+    checkInt(program, callFunction(program, "foo", []), 42);
+}
+
+tests.returnReferenceToLocalVariableWithNesting = () => {
+    let program = doPrep(`
+        test int foo()
+        {
+            return *bar() + *baz();
+        }
+
+        thread int* bar()
+        {
+            int a = 20;
+            return &a;
+        }
+
+        thread int* baz()
+        {
+            int a = 22;
+            return &a;
+        }
+    `);
+
+    checkInt(program, callFunction(program, "foo", []), 42);
+}
+
+tests.convertPtrToArrayRef = () => {
+    let program = doPrep(`
+        test int foo()
+        {
+            return bar()[0];
+        }
+
+        thread int[] bar()
+        {
+            int x = 42;
+            return @(&x);
+        }
+    `);
+
+    checkInt(program, callFunction(program, "foo", []), 42);
+}
+
+tests.convertLocalVariableToArrayRef = () => {
+    let program = doPrep(`
+        test int foo()
+        {
+            return bar()[0];
+        }
+
+        thread int[] bar()
+        {
+            int x = 42;
+            return @x;
+        }
+    `);
+
+    checkInt(program, callFunction(program, "foo", []), 42);
+}
+
+tests.referenceTakenToLocalVariableInEntryPointShouldntMoveAnything = () => {
+    let program = doPrep(`
+        test int foo()
+        {
+            int a = 42;
+            thread int* b = &a;
+            return *b;
+        }
+    `);
+
+    checkInt(program, callFunction(program, "foo", []), 42);
+};
+
 okToTest = true;
 
 let testFilter = /.*/; // run everything by default

Modified: trunk/Tools/WebGPUShadingLanguageRI/index.html (236360 => 236361)


--- trunk/Tools/WebGPUShadingLanguageRI/index.html	2018-09-21 21:23:26 UTC (rev 236360)
+++ trunk/Tools/WebGPUShadingLanguageRI/index.html	2018-09-21 21:46:02 UTC (rev 236361)
@@ -14,6 +14,7 @@
 <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