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=""