WebKit Bugzilla
Attachment 347094 Details for
Bug 187738
: [WHLSL] Test suite for Metal code generation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP
bug-187738-20180814110058.patch (text/plain), 427.64 KB, created by
Thomas Denney
on 2018-08-14 11:01:01 PDT
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Thomas Denney
Created:
2018-08-14 11:01:01 PDT
Size:
427.64 KB
patch
obsolete
>Subversion Revision: 234853 >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 30b733ae40036457ef84367906c047be00708795..b5eecf56d38567c383c6e220edfbf8e75be9470e 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,109 @@ >+2018-08-10 Thomas Denney <tdenney@apple.com> >+ >+ Adding WHLSL Compiler Tests >+ https://bugs.webkit.org/show_bug.cgi?id=187738 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * WebGPUShadingLanguageRI/Intrinsics.js: >+ (Intrinsics): >+ * WebGPUShadingLanguageRI/Metal/.gitignore: Added. >+ * WebGPUShadingLanguageRI/Metal/ArrayRefDefinition.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/CompileResult.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/ConstexprEmitter.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/Counter.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/Deinliner.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/FindTopLevelTypeAttributes.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/ForwardDeclarations.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/LineNumbers.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/MSLLexer.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/MSLTypeNamer.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/MetalCodegen.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/NameMangler.ts: Copied from Tools/WebGPUShadingLanguageRI/VisitingSet.js. >+ * WebGPUShadingLanguageRI/Metal/README.md: Added. >+ * WebGPUShadingLanguageRI/Metal/StructCodegen.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/StructFinalDefinition.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/StructForwardDeclaration.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/Token.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/TypeAttributes.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/TypeOfExpression.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/TypeSorter.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/TypeUnifier.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/VarOrFieldDeclaration.ts: Copied from Tools/WebGPUShadingLanguageRI/RecursionChecker.js. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/.gitignore: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/AppIcon.appiconset/Contents.json: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/Contents.json: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Base.lproj/Main.storyboard: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Default.whlsl: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Julia.whlsl: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Mandelbrot.whlsl: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Info.plist: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Metal equivalents/Shaders.metal: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.h: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/WHLSL.entitlements: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/_Shared.whlsl: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/main.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL Tests.xcodeproj/project.pbxproj: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/Info.plist: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/WHLSL_ToyTests.m: Added. >+ * WebGPUShadingLanguageRI/Metal/WHLSLLexer.ts: Added. >+ * WebGPUShadingLanguageRI/Metal/index.html: Added. >+ * WebGPUShadingLanguageRI/Metal/metal.css: Added. >+ (textarea, .code-source): >+ (input[type=button]): >+ (.code-source): >+ (td): >+ (body): >+ (h1, h2): >+ (table): >+ (.container-cell): >+ (th, td): >+ (.code-comment): >+ (.code-comment-note): >+ (.code-keyword, .code-type): >+ (.code-literal): >+ (.code-attribute): >+ (.code-whitespace): >+ (.code-error): >+ (.code-directive): >+ (.line-no): >+ (.line-no::before): >+ (.line): >+ * WebGPUShadingLanguageRI/Metal/tsconfig.json: Added. >+ * WebGPUShadingLanguageRI/RecursionChecker.js: >+ (RecursionChecker.prototype.visitFuncDef): >+ * WebGPUShadingLanguageRI/StandardLibrary.js: >+ * WebGPUShadingLanguageRI/Test.js: >+ * WebGPUShadingLanguageRI/VisitingSet.js: >+ (VisitingSet.prototype.shouldVisit): >+ > 2018-08-14 Aakash Jain <aakash_jain@apple.com> > > [ews-build] Add support for max_builds parameter for workers >diff --git a/Tools/WebGPUShadingLanguageRI/All.js b/Tools/WebGPUShadingLanguageRI/All.js >index 15dd7ccab94692a32acd27b9dac96c8a8f55d658..4c63e0ec59ebc76aeaa3d6c910bce2237f471ff4 100644 >--- a/Tools/WebGPUShadingLanguageRI/All.js >+++ b/Tools/WebGPUShadingLanguageRI/All.js >@@ -34,6 +34,7 @@ load("Visitor.js"); > load("CreateLiteral.js"); > load("CreateLiteralType.js"); > load("PropertyAccessExpression.js"); >+load("SwizzleOp.js"); > > load("AddressSpace.js"); > load("AnonymousVariable.js"); >diff --git a/Tools/WebGPUShadingLanguageRI/Intrinsics.js b/Tools/WebGPUShadingLanguageRI/Intrinsics.js >index 933dfe011302b0fbc8344994a1a5c1f77c052a6f..d6e788debeaa14dd42bd72eb8dd110371f986e6b 100644 >--- a/Tools/WebGPUShadingLanguageRI/Intrinsics.js >+++ b/Tools/WebGPUShadingLanguageRI/Intrinsics.js >@@ -155,7 +155,27 @@ class Intrinsics { > func => { > func.implementation = ([value]) => EPtr.box(value.loadValue() | 0); > }); >+ >+ this._map.set("native float log<>(float)", func => { >+ func.implementation = ([value]) => EPtr.box(Math.log(value.loadValue())); >+ }); > >+ this._map.set("native float pow<>(float,float)", func => { >+ func.implementation = ([a, b]) => EPtr.box(Math.pow(a.loadValue(), b.loadValue())); >+ }); >+ >+ this._map.set("native float sin<>(float)", func => { >+ func.implementation = ([a]) => EPtr.box(Math.pow(a.loadValue())); >+ }); >+ >+ this._map.set("native float cos<>(float)", func => { >+ func.implementation = ([a]) => EPtr.box(Math.pow(a.loadValue())); >+ }); >+ >+ this._map.set("native float atan2<>(float,float)", func => { >+ func.implementation = ([a, b]) => EPtr.box(Math.atan2(a.loadValue(), b.loadValue())); >+ }); >+ > this._map.set( > "native operator<> int32(uint8)", > func => { >@@ -541,7 +561,6 @@ class Intrinsics { > }, > func.implementationData = swizzle; > }); >- console.log(swizzle.toString()); > } > } > >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/.gitignore b/Tools/WebGPUShadingLanguageRI/Metal/.gitignore >new file mode 100644 >index 0000000000000000000000000000000000000000..35434ffb59d05621b1d662b7d989a497bf8dd9fa >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/.gitignore >@@ -0,0 +1,2 @@ >+compiler.js >+compiler.js.map >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/ArrayRefDefinition.ts b/Tools/WebGPUShadingLanguageRI/Metal/ArrayRefDefinition.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..e3a9f38c961116fbe8f852c564bf20277148811a >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/ArrayRefDefinition.ts >@@ -0,0 +1,50 @@ >+/* >+ * 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. >+ */ >+ >+// Writes the definitions of the structures used for the different array ref types present in the program. >+class ArrayRefDefinition { >+ private _arrayRefType: ArrayRefType; >+ private _typeNamer: MSLTypeNamer; >+ >+ constructor(node, typeNamer) >+ { >+ this._arrayRefType = node; >+ this._typeNamer = typeNamer; >+ } >+ >+ get arrayRefType() >+ { >+ return this._arrayRefType; >+ } >+ >+ toString() >+ { >+ let src = `struct ${this._typeNamer.uniqueTypeId(this.arrayRefType)} {\n`; >+ src += ` ${this.arrayRefType.addressSpace} ${this._typeNamer.mslTypeName(this.arrayRefType.elementType)}* ptr;\n`; >+ src += ` size_t length;\n`; >+ src += `};`; >+ return src; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/CompileResult.ts b/Tools/WebGPUShadingLanguageRI/Metal/CompileResult.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..aad082870c2dd0439f0626766c3b836a1b6cf2bf >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/CompileResult.ts >@@ -0,0 +1,65 @@ >+/* >+ * 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. >+ */ >+ >+class CompileResult { >+ >+ private _metalShaderLanguageSource: string; >+ private _error: Error; >+ private _originalFunctionNameToMangledNames: any; >+ private _functionSources: Map<string, string>; >+ >+ constructor(src: string, err: Error, mangledNameMap: any, functionSources: Map<string, string>) >+ { >+ this._metalShaderLanguageSource = src; >+ this._error = err; >+ this._originalFunctionNameToMangledNames = mangledNameMap; >+ this._functionSources = functionSources; >+ } >+ >+ get metalShaderLanguageSource(): string >+ { >+ return this._metalShaderLanguageSource; >+ } >+ >+ get error(): Error >+ { >+ return this._error; >+ } >+ >+ get originalFunctionNameToMangledNames() >+ { >+ return this._originalFunctionNameToMangledNames; >+ } >+ >+ get functionSources() >+ { >+ return this._functionSources; >+ } >+ >+ get didSucceed() >+ { >+ return this._error == null; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/ConstexprEmitter.ts b/Tools/WebGPUShadingLanguageRI/Metal/ConstexprEmitter.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..8ae12f389a09e7ab87ca18039984a7904e5ee664 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/ConstexprEmitter.ts >@@ -0,0 +1,48 @@ >+/* >+ * 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. >+ */ >+ >+// Used in scenarios where having an auxiliary variable is not possible (e.g. switch cases). >+class ConstexprEmitter extends Visitor >+{ >+ visitBoolLiteral(node) >+ { >+ return node.value.toString(); >+ } >+ >+ visitEnumLiteral(node) >+ { >+ return node.member.value.toString(); >+ } >+ >+ visitGenericLiteral(node) >+ { >+ return node.value.toString(); >+ } >+ >+ visitNullLiteral(node) >+ { >+ return "(nullptr)"; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/Counter.ts b/Tools/WebGPUShadingLanguageRI/Metal/Counter.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..9ef38cdf412082487991237b7d7ab1b916468e86 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/Counter.ts >@@ -0,0 +1,41 @@ >+/* >+ * 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. >+ */ >+ >+// Provides unique names to variables, functions, and types. >+class Counter { >+ private _prefix: string; >+ private _value: number; >+ >+ constructor(prefix: string) >+ { >+ this._prefix = prefix; >+ this._value = 0; >+ } >+ >+ fresh(): string >+ { >+ return `${this._prefix}${this._value++}`; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/Deinliner.ts b/Tools/WebGPUShadingLanguageRI/Metal/Deinliner.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..b6d261a70d6f9b9e95a1bb9a64b9916e4efe292d >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/Deinliner.ts >@@ -0,0 +1,392 @@ >+/* >+ * 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. >+ */ >+ >+// Determines whether a function has reducible control flow or potential early returns. >+// This is a conservative estimate (e.g. in the case of loops). >+function functionLikeBlockCanBeInlined(node: FunctionLikeBlock) >+{ >+ enum ReturnStyle { >+ Never, >+ SometimesEarly, >+ Always >+ }; >+ >+ // A loop body might always return, but the loop body is only executed if the loop's condition holds. >+ // We therefore downgrade our certainty for the whole loop. >+ const beConservativeWithAlways = (a: ReturnStyle) => { >+ return a == ReturnStyle.Always ? ReturnStyle.SometimesEarly : a; >+ }; >+ >+ // Used wheere statement a immediately preceeds statement b. >+ const combineReturnStylesForSubsequents = (a: ReturnStyle, b: ReturnStyle) => { >+ if (a == ReturnStyle.Always || a == ReturnStyle.SometimesEarly) >+ return a; >+ return b; >+ }; >+ >+ // Used when statement a is the if branch, statement b is the else branch >+ const combineReturnStylesForAlternatives = (a: ReturnStyle, b: ReturnStyle) => { >+ switch (a) { >+ case ReturnStyle.Never: >+ switch (b) { >+ case ReturnStyle.Never: >+ return ReturnStyle.Never; >+ case ReturnStyle.Always: >+ return ReturnStyle.SometimesEarly; >+ case ReturnStyle.SometimesEarly: >+ return ReturnStyle.SometimesEarly; >+ } >+ case ReturnStyle.SometimesEarly: >+ return ReturnStyle.SometimesEarly; >+ case ReturnStyle.Always: >+ switch (b) { >+ case ReturnStyle.Never: >+ case ReturnStyle.SometimesEarly: >+ return ReturnStyle.SometimesEarly; >+ case ReturnStyle.Always: >+ return ReturnStyle.Always; >+ } >+ } >+ } >+ >+ class ReturnStyleVisitor extends Visitor { >+ private _visitList(list: Node[]) >+ { >+ let style = ReturnStyle.Never; >+ for (let statement of list) { >+ style = combineReturnStylesForSubsequents(style, returnStyleForNodeOrNull(statement)); >+ if (style != ReturnStyle.Never) >+ return style; >+ } >+ return style; >+ } >+ >+ visitAnonymousVariable(node: AnonymousVariable) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitAssignment(node: Assignment) >+ { >+ return this._visitList([ node.lhs, node.rhs ]); >+ } >+ >+ visitBlock(node: Block) >+ { >+ return this._visitList(node.statements); >+ } >+ >+ visitBreak(node: Break) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitCallExpression(node: CallExpression) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitCommaExpression(node: CommaExpression) >+ { >+ return this._visitList(node.list); >+ } >+ >+ visitContinue(node: Continue) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitDereferenceExpression(node: DereferenceExpression) >+ { >+ return returnStyleForNodeOrNull(node.ptr); >+ } >+ >+ visitDotExpression(node: DotExpression) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitDoWhileLoop(node: DoWhileLoop) >+ { >+ return beConservativeWithAlways(this._visitList([ node.body, node.conditional ])); >+ } >+ >+ visitForLoop(node: ForLoop) >+ { >+ return beConservativeWithAlways(this._visitList([ node.initialization, node.condition, node.body, node.increment ])); >+ } >+ >+ visitFuncDef(node: FuncDef) >+ { >+ return returnStyleForNodeOrNull(node.body); >+ } >+ >+ visitFunctionLikeBlock(node: FunctionLikeBlock) >+ { >+ return returnStyleForNodeOrNull(node.func) == ReturnStyle.SometimesEarly ? ReturnStyle.SometimesEarly : ReturnStyle.Never; >+ } >+ >+ visitGenericLiteral(node: GenericLiteral) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitIdentityExpression(node: IdentityExpression) >+ { >+ return returnStyleForNodeOrNull(node.target); >+ } >+ >+ visitIfStatement(node: IfStatement) >+ { >+ const conditional = returnStyleForNodeOrNull(node.conditional); >+ const body = returnStyleForNodeOrNull(node.body); >+ const elseBody = returnStyleForNodeOrNull(node.elseBody); >+ return combineReturnStylesForSubsequents(conditional, combineReturnStylesForAlternatives(body, elseBody)); >+ } >+ >+ visitIndexExpression(node: IndexExpression) >+ { >+ return this._visitList([ node.array, node.index ]); >+ } >+ >+ visitLogicalExpression(node: LogicalExpression) >+ { >+ return this._visitList([ node.left, node.right ]); >+ } >+ >+ visitLogicalNot(node: LogicalNot) >+ { >+ return returnStyleForNodeOrNull(node.operand); >+ } >+ >+ visitMakeArrayRefExpression(node: MakeArrayRefExpression) >+ { >+ return returnStyleForNodeOrNull(node.lValue); >+ } >+ >+ visitMakePtrExpression(node: MakePtrExpression) >+ { >+ return returnStyleForNodeOrNull(node.lValue); >+ } >+ >+ visitNullLiteral(node: NullLiteral) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitReturn(node: Return) >+ { >+ return ReturnStyle.Always; >+ } >+ >+ visitSwitchCase(node: SwitchCase) >+ { >+ return returnStyleForNodeOrNull(node.body); >+ } >+ >+ visitSwitchStatement(node: SwitchStatement) >+ { >+ >+ // return within switch statements is awkward, so we prevent their inlining. >+ // Its fine if the switch is a top level statement of the function and every branch returns, >+ // including a default case, but if that switch is inside a loop or similar we start hitting issues. >+ return beConservativeWithAlways(this._visitList(node.switchCases)); >+ } >+ >+ visitTrapStatement(node: TrapStatement) >+ { >+ return ReturnStyle.Always; >+ } >+ >+ visitVariableDecl(node: VariableDecl) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitVariableRef(node: VariableRef) >+ { >+ return ReturnStyle.Never; >+ } >+ >+ visitWhileLoop(node: WhileLoop) >+ { >+ return beConservativeWithAlways(this._visitList([ node.conditional, node.body ])); >+ } >+ >+ visitArrayRefType(node: ArrayRefType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitArrayRefType"); >+ } >+ >+ visitArrayType(node: ArrayType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitArrayType"); >+ } >+ >+ visitBoolLiteral(node: BoolLiteral) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitBoolLiteral"); >+ } >+ >+ visitConstexprTypeParameter(node: ConstexprTypeParameter) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitConstexprTypeParameter"); >+ } >+ >+ visitConvertPtrToArrayRefExpression(node: ConvertPtrToArrayRefExpression) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitConvertPtrToArrayRefExpression"); >+ } >+ >+ visitElementalType(node: ElementalType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitElementalType"); >+ } >+ >+ visitEnumLiteral(node: EnumLiteral) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitEnumLiteral"); >+ } >+ >+ visitEnumMember(node: EnumMember) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitEnumMember"); >+ } >+ >+ visitEnumType(node: EnumType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitEnumType"); >+ } >+ >+ visitField(node: Field) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitField"); >+ } >+ >+ visitFunc(node: Func) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitFunc"); >+ } >+ >+ visitFuncParameter(node: FuncParameter) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitFuncParameter"); >+ } >+ >+ visitGenericLiteralType(node: GenericLiteralType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitGenericLiteralType"); >+ } >+ >+ visitNativeFunc(node: NativeFunc) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitNativeFunc"); >+ } >+ >+ visitNativeFuncInstance(node: NativeFuncInstance) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitNativeFuncInstance"); >+ } >+ >+ visitNativeType(node: NativeType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitNativeType"); >+ } >+ >+ visitNativeTypeInstance(node: NativeTypeInstance) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitNativeTypeInstance"); >+ } >+ >+ visitNullType(node: NullType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitNullType"); >+ } >+ >+ visitProgram(node: Program) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitProgram"); >+ } >+ >+ visitProtocolDecl(node: ProtocolDecl) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitProtocolDecl"); >+ } >+ >+ visitProtocolFuncDecl(node: ProtocolFuncDecl) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitProtocolFuncDecl"); >+ } >+ >+ visitProtocolRef(node: ProtocolRef) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitProtocolRef"); >+ } >+ >+ visitPtrType(node: PtrType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitPtrType"); >+ } >+ >+ visitReadModifyWriteExpression(node: ReadModifyWriteExpression) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitReadModifyWriteExpression"); >+ } >+ >+ visitReferenceType(node: ReferenceType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitReferenceType"); >+ } >+ >+ visitStructType(node: StructType) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitStructType"); >+ } >+ >+ visitTypeDef(node: TypeDef) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitTypeDef"); >+ } >+ >+ visitTypeRef(node: TypeRef) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitTypeRef"); >+ } >+ >+ visitTypeVariable(node: TypeVariable) >+ { >+ throw new Error("Unimplemented ReturnStyleVisitor.visitTypeVariable"); >+ } >+ } >+ >+ const returnStyleVisitor = new ReturnStyleVisitor(); >+ >+ function returnStyleForNodeOrNull(node: Node) >+ { >+ return node ? Node.visit(node, returnStyleVisitor) : ReturnStyle.Never; >+ } >+ >+ return returnStyleForNodeOrNull(node) != ReturnStyle.SometimesEarly; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/FindTopLevelTypeAttributes.ts b/Tools/WebGPUShadingLanguageRI/Metal/FindTopLevelTypeAttributes.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..cc72640576339accbb6daf5a1aebe82f98933f70 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/FindTopLevelTypeAttributes.ts >@@ -0,0 +1,91 @@ >+/* >+ * 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. >+ */ >+ >+// Provides lookup for all the top level types in the program. >+class FindTopLevelTypeAttributes extends Visitor { >+ private _typeUnifier : TypeUnifier; >+ private _typeAttributeMap : Map<string, TypeAttributes>; >+ >+ constructor(functionDefs, typeUnifier) >+ { >+ super(); >+ this._typeUnifier = typeUnifier; >+ >+ this._typeAttributeMap = new Map(); >+ >+ for (let func of functionDefs) >+ Node.visit(func.func, this); >+ } >+ >+ _keyForType(type) >+ { >+ return this._typeUnifier.uniqueTypeId(type); >+ } >+ >+ hasAttributesForType(type) >+ { >+ return this._typeAttributeMap.has(this._keyForType(type)); >+ } >+ >+ attributesForType(type) >+ { >+ const key = this._keyForType(type); >+ let attrs = this._typeAttributeMap.get(key); >+ if (!attrs) { >+ attrs = new TypeAttributes(type); >+ this._typeAttributeMap.set(key, attrs); >+ } >+ return attrs; >+ } >+ >+ visitFuncDef(func) >+ { >+ switch (func.shaderType) { >+ case "vertex": >+ this.visitVertexShader(func); >+ break; >+ case "fragment": >+ this.visitFragmentShader(func); >+ break; >+ } >+ } >+ >+ private visitVertexShader(func) >+ { >+ this.attributesForType(func.returnType).isVertexOutputOrFragmentInput = true; >+ for (let param of func.parameters) >+ this.attributesForType(param.type).isVertexAttribute = true; >+ } >+ >+ private visitFragmentShader(func) >+ { >+ for (let param of func.parameters) >+ this.attributesForType(param.type).isVertexOutputOrFragmentInput = true; >+ >+ this.attributesForType(func.returnType).isFragmentOutput = true; >+ } >+ >+ // TODO: Handle compute shaders >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/ForwardDeclarations.ts b/Tools/WebGPUShadingLanguageRI/Metal/ForwardDeclarations.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..0d18099dd0fd688e9a8abd960be987d4dec70586 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/ForwardDeclarations.ts >@@ -0,0 +1,352 @@ >+/* >+ * 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. >+ */ >+ >+// To avoid having to convert all of the existing classes in the interpreter to >+// TypeScript we instead just include all of the methods that we need here to >+// avoid type errors with TypeScript. >+ >+declare class Console { >+ log(message: string, ...args: any[]); >+} >+ >+declare const console: Console; >+ >+declare class Visitor { >+ visitAnonymousVariable(node: AnonymousVariable); >+ visitArrayRefType(node: ArrayRefType); >+ visitArrayType(node: ArrayType); >+ visitAssignment(node: Assignment); >+ visitBlock(node: Block); >+ visitBoolLiteral(node: BoolLiteral); >+ visitBreak(node: Break); >+ visitCallExpression(node: CallExpression); >+ visitCommaExpression(node: CommaExpression); >+ visitConstexprTypeParameter(node: ConstexprTypeParameter); >+ visitContinue(node: Continue); >+ visitConvertPtrToArrayRefExpression(node: ConvertPtrToArrayRefExpression); >+ visitDereferenceExpression(node: DereferenceExpression); >+ visitDotExpression(node: DotExpression); >+ visitDoWhileLoop(node: DoWhileLoop); >+ visitElementalType(node: ElementalType); >+ visitEnumLiteral(node: EnumLiteral); >+ visitEnumMember(node: EnumMember); >+ visitEnumType(node: EnumType); >+ visitField(node: Field); >+ visitForLoop(node: ForLoop); >+ visitFunc(node: Func); >+ visitFuncDef(node: FuncDef); >+ visitFuncParameter(node: FuncParameter); >+ visitFunctionLikeBlock(node: FunctionLikeBlock); >+ visitGenericLiteral(node: GenericLiteral); >+ visitGenericLiteralType(node: GenericLiteralType); >+ visitIdentityExpression(node: IdentityExpression); >+ visitIfStatement(node: IfStatement); >+ visitIndexExpression(node: IndexExpression); >+ visitLogicalExpression(node: LogicalExpression); >+ visitLogicalNot(node: LogicalNot); >+ visitMakeArrayRefExpression(node: MakeArrayRefExpression); >+ visitMakePtrExpression(node: MakePtrExpression); >+ visitNativeFunc(node: NativeFunc); >+ visitNativeFuncInstance(node: NativeFuncInstance); >+ visitNativeType(node: NativeType); >+ visitNativeTypeInstance(node: NativeTypeInstance); >+ visitNullLiteral(node: NullLiteral); >+ visitNullType(node: NullType); >+ visitProgram(node: Program); >+ visitProtocolDecl(node: ProtocolDecl); >+ visitProtocolFuncDecl(node: ProtocolFuncDecl); >+ visitProtocolRef(node: ProtocolRef); >+ visitPtrType(node: PtrType); >+ visitReadModifyWriteExpression(node: ReadModifyWriteExpression); >+ visitReferenceType(node: ReferenceType); >+ visitReturn(node: Return); >+ visitStructType(node: StructType); >+ visitSwitchCase(node: SwitchCase); >+ visitSwitchStatement(node: SwitchStatement); >+ visitTrapStatement(node: TrapStatement); >+ visitTypeDef(node: TypeDef); >+ visitTypeRef(node: TypeRef); >+ visitTypeVariable(node: TypeVariable); >+ visitVariableDecl(node: VariableDecl); >+ visitVariableRef(node: VariableRef); >+ visitWhileLoop(node: WhileLoop); >+} >+ >+declare class Rewriter {} >+ >+declare class Lexer { >+ constructor(a, b, c, d); >+ next(): any; >+} >+ >+declare class Assignment extends Node { >+ lhs: Node; >+ rhs: Node; >+} >+ >+declare class AnonymousVariable extends Node {} >+ >+declare class ArrayRefType extends Type { >+ constructor(origin, addressSpace, elementType); >+ >+ addressSpace: string; >+ elementType: Type; >+} >+ >+declare class ArrayType extends Type { >+ constructor(origin, elementType, numElements); >+ >+ elementType: Type; >+ numElements: any; >+} >+ >+declare class Block extends Node { >+ constructor(origin: any); >+ >+ add(node: Node); >+ >+ statements: Node[]; >+} >+ >+declare class BoolLiteral extends Node { >+ constructor(origin, value); >+} >+ >+declare class CallExpression extends Node { >+ constructor(origin, name, typeArguments, argumentList); >+ >+ actualTypeArguments: any; >+ instantiatedActualTypeArguments: any; >+ argumentTypes: any; >+ func: any; >+ nativeFuncInstance: any; >+ possibleOverloads: any; >+ resultType: any; >+ resultEPtr: any; >+ >+ setCastData(any); >+} >+ >+declare class CommaExpression extends Node { >+ list: Node[]; >+} >+ >+declare class DereferenceExpression extends Node { >+ ptr: Node; >+} >+ >+declare class DoWhileLoop extends Node { >+ constructor(origin, body, conditional); >+ >+ body: Node; >+ conditional: Node; >+} >+ >+declare class EnumType extends Type { >+ constructor(origin, name, baseType); >+} >+ >+declare class Field extends Node { >+ constructor(origin, name, type); >+ >+ name: string; >+ type: Type; >+} >+ >+declare class ForLoop extends Node { >+ initialization: Node; >+ condition: Node; >+ increment: Node; >+ body: Node; >+} >+ >+declare class Func extends Node { >+ constructor(origin, name, returnType, typeParameters, parameters, isCast, shaderType); >+ >+ name: string; >+ origin: Origin; >+ parameters: FuncParameter[]; >+ returnType: Type; >+ shaderType: string; >+ isEntryPoint: boolean; >+} >+ >+declare class FunctionLikeBlock extends Node { >+ func: Func; >+} >+ >+declare class FuncDef extends Func { >+ constructor(origin, name, returnType, typeParameters, parameters, body, isCast, shaderType); >+ >+ body: Node; >+} >+ >+declare class FuncInstantiator { >+ instances: any[]; >+} >+ >+declare class FuncParameter extends Value { >+ constructor(origin: Origin, name: string, type: Type); >+ >+ origin: Origin; >+ name: string; >+ type: Type; >+ varIsLValue: boolean; >+} >+ >+declare class IdentityExpression extends Node { >+ target: Node; >+} >+ >+declare class IfStatement { >+ constructor(origin, conditional, body, elseBody); >+ >+ conditional: Node; >+ body: Node; >+ elseBody: Node; >+} >+ >+declare class IndexExpression extends Node { >+ array: Node; >+ index: Node; >+} >+ >+declare class LogicalExpression extends Node { >+ text: string; >+ left: Node; >+ right: Node; >+} >+ >+declare class LogicalNot extends Node { >+ operand: Node; >+} >+ >+declare class MakeArrayRefExpression extends Node { >+ lValue: any; >+ numElements: any; >+} >+ >+declare class MakePtrExpression extends Node { >+ lValue: any; >+} >+ >+declare class NativeFuncInstance extends Node { >+ constructor(func, returnType, parameters, isCast, shaderType, implementationData); >+} >+ >+declare class Node { >+ static visit(func: any, visitor: Visitor | Rewriter); >+ visit(visitor: Visitor); >+ >+ origin: Origin; >+} >+ >+declare class Origin { >+ index: number; >+} >+ >+declare class Program { >+ topLevelStatements: Node[]; >+ functions: Func[]; >+ types: Type[]; >+ funcInstantiator: FuncInstantiator; >+} >+ >+declare class PtrType extends Type { >+ constructor(origin, addressSpace, elementType); >+} >+ >+declare class StructType extends Type { >+ constructor(origin, name, typeParameters); >+ >+ fieldMap: Map<string, Field>; >+ fields: Field[]; >+ >+ add(field: Field); >+} >+ >+declare class SwitchCase extends Node { >+ isDefault: boolean; >+ value: Node; >+ body: Node; >+} >+ >+declare class SwitchStatement extends Node { >+ switchCases: SwitchCase[]; >+} >+ >+declare class SwizzleOp { >+ constructor(outSize: number, components: string[], inSize: number); >+ >+ outSize: number; >+ components: string[]; >+ inSize: number; >+} >+ >+declare class Type extends Node { >+ name: string; >+ isArray: boolean; >+} >+ >+declare class VariableRef extends Node {} >+ >+declare class Value extends Node {} >+ >+declare class WhileLoop extends Node { >+ constructor(origin, condition, body); >+ >+ conditional: Node; >+ body: Node; >+} >+ >+declare function prepare(file: string, lineOffset: number, src: string): Program; >+ >+// TODO >+declare class Break extends Node {} >+declare class ConstexprTypeParameter extends Node {} >+declare class Continue extends Node {} >+declare class ConvertPtrToArrayRefExpression extends Node {} >+declare class DotExpression extends Node {} >+declare class ElementalType extends Node {} >+declare class EnumLiteral extends Node {} >+declare class EnumMember extends Node {} >+declare class GenericLiteral extends Node {} >+declare class GenericLiteralType extends Node {} >+declare class NativeFunc extends Node {} >+declare class NativeType extends Node {} >+declare class NativeTypeInstance extends Node {} >+declare class NullLiteral extends Node {} >+declare class NullType extends Node {} >+declare class ProtocolDecl extends Node {} >+declare class ProtocolFuncDecl extends Node {} >+declare class ProtocolRef extends Node {} >+declare class ReadModifyWriteExpression extends Node {} >+declare class ReferenceType extends Node {} >+declare class Return extends Node {} >+declare class TrapStatement extends Node {} >+declare class TypeDef extends Node {} >+declare class TypeRef extends Node {} >+declare class TypeVariable extends Node {} >+declare class VariableDecl extends Node {} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/LineNumbers.ts b/Tools/WebGPUShadingLanguageRI/Metal/LineNumbers.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..9c7c988439ef401c226839f1053c03e1f6779191 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/LineNumbers.ts >@@ -0,0 +1,38 @@ >+/* >+ * 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. >+ */ >+ >+// This must be called on the original WHLSL source before MSL compilation >+// to allow translation from character indices to line numbers. >+function lineNumbers(src: string): number[] >+{ >+ const lineNumbers = []; >+ let lineNumber = 1; >+ for (let i = 0; i < src.length; i++) { >+ lineNumbers.push(lineNumber); >+ if (src[i] == '\n') >+ lineNumber++; >+ } >+ return lineNumbers; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..6b57a400f636472c8a6497f3d76bc50104bc0dd1 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.ts >@@ -0,0 +1,149 @@ >+/* >+ * 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. >+ */ >+ >+// Emits code for for the first line of a function declaration or definition. >+class MSLFunctionDeclaration { >+ private _funcMangler: NameMangler; >+ private _func: FuncDef; >+ private _typeArgs: Type[]; >+ private _typeNamer: MSLTypeNamer; >+ private _mangledName: string; >+ private _lineNumbers: number[]; >+ private _typeAttributes: FindTopLevelTypeAttributes; >+ >+ constructor(funcMangler, funcDef, typeArguments, typeNamer, mangledName, lineNos, typeAttributes) >+ { >+ this._funcMangler = funcMangler; >+ this._func = funcDef; >+ this._typeArgs = typeArguments; >+ this._typeNamer = typeNamer; >+ this._mangledName = mangledName; >+ this._lineNumbers = lineNos; >+ this._typeAttributes = typeAttributes; >+ } >+ >+ get funcMangler(): NameMangler >+ { >+ return this._funcMangler; >+ } >+ >+ get func(): FuncDef >+ { >+ return this._func; >+ } >+ >+ get mangledName(): string >+ { >+ return this._mangledName; >+ } >+ >+ get typeNamer(): MSLTypeNamer >+ { >+ return this._typeNamer; >+ } >+ >+ get lineNumbers(): number[] >+ { >+ return this._lineNumbers; >+ } >+ >+ get typeAttributes(): FindTopLevelTypeAttributes >+ { >+ return this._typeAttributes; >+ } >+ >+ get isVertexShader() >+ { >+ return this._func.shaderType == "vertex"; >+ } >+ >+ get paramMap() >+ { >+ const map = new Map(); >+ let counter = 0; >+ for (let param of this._func.parameters) >+ map.set(param.name, `P${counter++}`); >+ return map; >+ } >+ >+ commentLine() >+ { >+ const params = []; >+ for (let paramName of this.paramMap.keys()) >+ params.push(paramName); >+ let line = `// ${this._func.name}(${params.join(", ")})`; >+ if (this._lineNumbers && this._func.origin.index && this._lineNumbers[this._func.origin.index]) >+ line += ` @ line ${this._lineNumbers[this._func.origin.index]}`; >+ return line + "\n"; >+ } >+ >+ toString() >+ { >+ let declLine = this.commentLine(); >+ >+ // TODO: Support shader types other than fragment and vertex. >+ // What WSL calls `compute` shaders Metal calls `kernel` shaders. >+ // We're only focussing on `vertex` and `fragment` for now. >+ if (this._func.shaderType === "vertex" || this._func.shaderType === "fragment") >+ declLine += `${this._func.shaderType} `; >+ declLine += `${this._typeNamer.mslTypeName(this._func.returnType)} `; >+ declLine += this._mangledName; >+ let typeArgIds = []; >+ for (let arg of this._typeArgs) >+ typeArgIds.push(this._typeNamer.uniqueTypeId(arg)); >+ if (typeArgIds.length) >+ declLine += "_" + typeArgIds.join("_"); >+ declLine += "(" >+ >+ let params = []; >+ const paramMap = this.paramMap; >+ for (let param of this._func.parameters) { >+ let pStr = `${this._typeNamer.mslTypeName(param.type)} ${paramMap.get(param.name)}`; >+ // FIXME: The parser doesn't currently support vertex shaders having uint parameters, so this doesn't work. >+ if (this.parameterIsVertexId(param) && this.isVertexShader) >+ pStr += " [[vertex_id]]"; >+ else if (this.parameterIsAttribute(param)) >+ pStr += " [[stage_in]]"; >+ params.push(pStr); >+ } >+ >+ declLine += params.join(", ") + ")"; >+ >+ return declLine; >+ } >+ >+ parameterIsAttribute(node) >+ { >+ // We currently assuming that all parameters to entry points are attributes. >+ // TODO: Better logic for this, i.e. support samplers. >+ return this._func.isEntryPoint; >+ } >+ >+ parameterIsVertexId(node) >+ { >+ // FIXME: This isn't final, and isn't formally specified yet. >+ return this.isVertexShader && node.name == "wsl_vertexID" && node.type.name == "uint32"; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..d77b5d8839e50ce60e980a5979c45ff8a392d0f0 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.ts >@@ -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. >+ */ >+ >+class MSLFunctionDefinition extends MSLFunctionDeclaration >+{ >+ toString() >+ { >+ let src = super.toString(); >+ src += "\n{\n"; >+ let emitter = new MSLStatementEmitter(this.funcMangler, this.typeNamer, this.func, this.paramMap, this.func.name, this.lineNumbers, this.typeAttributes); >+ src += emitter.indentedSource(); >+ src += "}"; >+ return src; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..57c6f81353c1f381f967345f8987f3cfb91da518 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionForwardDeclaration.ts >@@ -0,0 +1,32 @@ >+/* >+ * 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. >+ */ >+ >+class MSLFunctionForwardDeclaration extends MSLFunctionDeclaration >+{ >+ toString() >+ { >+ return super.toString() + ";" >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLLexer.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLLexer.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..8f602669d76bf59a7988aff5360c7c610573167d >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLLexer.ts >@@ -0,0 +1,125 @@ >+/* >+ * 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. >+ */ >+ >+// Does sufficient lexing for the output of the compiler, not for MSL in general! >+class MSLLexer { >+ private _tokens: Token[]; >+ >+ constructor(src) >+ { >+ this._tokens = this._lex(src); >+ } >+ >+ get tokens(): Token[] >+ { >+ return this._tokens; >+ } >+ >+ private get commentMatchers() >+ { >+ return [ >+ { type: "comment", regex: /^(\/\/|\/\*)(\s+)?/ }, >+ { type: "comment-note", regex: /^(TODO:|FIXME:)/ }, >+ { type: "comment", regex: /.*(\n|$)/ } >+ ] >+ } >+ >+ private get defaultMatchers() >+ { >+ return [ >+ { type: "comment", regex: /^\/\/(.*?)(\n|$)/, inner: this.commentMatchers }, >+ { type: "directive", regex: /^#(.*?)(\n|$)/ }, >+ { type: "whitespace", regex: /^\s+/ }, >+ { type: "literal", regex: /^([0-9]+)(\.([0-9]*?))?/ }, >+ { type: "type", regex: /^(char|uchar|struct|vertex|fragment|uint[0-9]?|int[0-9]?|float[0-9]?|void|bool|const|constant|thread|threadgroup|device|size_t)/ }, >+ { type: "keyword", regex: /^(return|if|else|do|while|switch|case|default|break|continue|nullptr|true|false|using|namespace)/ }, >+ { type: "attribute", regex: /^\[\[([A-z][A-z_\(\)0-9]+)\]\]/, inner: [ >+ { type: "attribute", regex: /^\[\[[A-z]+\(/ }, >+ { type: "literal", regex: /^[0-9]+/ }, >+ { type: "attribute", regex: /^\)\]\]/ }, >+ { type: "attribute", regex: /^\[\[([A-z][A-z_\(\)0-9]+)\]\]/ } >+ ] }, >+ { type: "error", regex: /^undefined/ }, >+ { type: "identifier", regex: /^[A-z]([A-z0-9_]*)?/ }, >+ { type: "punctuation", regex: /^(;|\.|\(|\)|,|\+|\-|=|->|>|<|\!|\}|\{|\*|\?|\:|\[|\])/}, >+ { type: "unknown", regex: /^(.*?)(\n|$)/ } >+ ]; >+ } >+ >+ private _lex(src, initMatchers = null): Token[] >+ { >+ const tokens: Token[] = []; >+ const matchers = initMatchers ? initMatchers : this.defaultMatchers; >+ >+ const startOfMultilineComment = /^\/\*/; >+ const endOfMultilineComment = /\*\//; >+ >+ const originalLength = src.length; >+ >+ while (src.length) { >+ // Special case for multiline comments. >+ const startMatch = startOfMultilineComment.exec(src); >+ if (startMatch) { >+ const endMatch = endOfMultilineComment.exec(src); >+ if (endMatch) { >+ // Important to ignore the first two characters to avoid recursion. >+ tokens.push(new Token("comment", startMatch[0], originalLength - src.length)); >+ const commentText = src.substring(2, endMatch.index + 2); >+ for (let innerTok of this._lex(commentText, this.commentMatchers)) >+ tokens.push(innerTok); >+ src = src.substring(endMatch.index + 2); >+ } else >+ throw new Error("Unmatched multiline comment"); >+ } >+ >+ let didMatch = false; >+ for (let matcher of matchers) { >+ const match = matcher.regex.exec(src); >+ if (match) { >+ if (matcher.inner) { >+ let innerToks = this._lex(match[0], matcher.inner); >+ for (let innerTok of innerToks) { >+ innerTok.startIndex += originalLength - src.length; >+ tokens.push(innerTok); >+ } >+ } else >+ tokens.push(new Token(matcher.type, match[0], originalLength - src.length)); >+ src = src.substring(match[0].length); >+ didMatch = true; >+ break; >+ } >+ } >+ if (!didMatch) >+ throw new Error(`Nothing matched ${src}`); >+ } >+ >+ return tokens; >+ } >+} >+ >+function lexMsl(msl: string): Token[] >+{ >+ return new MSLLexer(msl).tokens; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..782d88b6fe6cbcb36de9fe52e468945aa512be08 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.ts >@@ -0,0 +1,814 @@ >+/* >+ * 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. >+ */ >+ >+class MSLStatementEmitter extends Visitor { >+ private _funcMangler: NameMangler; >+ private _typeNamer: MSLTypeNamer; >+ private _func: Func; >+ private _nameMap: Map<string, string>; >+ private _nameMapStack: Array<Map<string, string>>; >+ private _debugName: string; >+ private _lineNumbers: number[]; >+ private _typeAttributes: FindTopLevelTypeAttributes; >+ private _resultVar: string; >+ private _counter : Counter; >+ private _indentLevel: number; >+ private _lines: string[]; >+ private _ancestorReturnType : Type; >+ private _actualResult: string; >+ private _loopConditionVariableStack: string[] = []; >+ private _loopConditionNodeStack: Node[] = []; >+ private _loopIncrementNodeStack: Node[] = []; >+ >+ constructor(funcMangler: NameMangler, typeNamer: MSLTypeNamer, func: Func, paramMap: Map<string, string>, debugName: string, lineNos: number[], typeAttributes: FindTopLevelTypeAttributes, resultVar: string = null, counter: Counter = null, ancestorReturnType: Type = null) >+ { >+ super(); >+ this._funcMangler = funcMangler; >+ this._typeNamer = typeNamer; >+ this._func = func; >+ this._nameMap = paramMap; >+ this._nameMapStack = []; >+ this._debugName = debugName; >+ this._lineNumbers = lineNos; >+ this._typeAttributes = typeAttributes; >+ this._resultVar = resultVar; >+ this._counter = counter ? counter : new Counter("V"); >+ this._indentLevel = 0; >+ this._lines = []; >+ this._ancestorReturnType = ancestorReturnType ? ancestorReturnType : func.returnType; >+ >+ this._actualResult = Node.visit(this._func, this); >+ } >+ >+ get ancestorReturnType() >+ { >+ return this._ancestorReturnType; >+ } >+ >+ private _emitReturnZeroValue() >+ { >+ if (this.ancestorReturnType.name === "void") >+ this._add(`return;`); >+ else { >+ const resultVar = this._fresh(); >+ this._add(`${this._typeNamer.mslTypeName(this.ancestorReturnType)} ${resultVar};`); >+ this._zeroInitialize(this.ancestorReturnType, resultVar); >+ this._add(`return ${resultVar};`); >+ } >+ } >+ >+ // MSL uses the same default initialization rules as C++14, which means that the default value >+ // of a local variable is not deterministic. Therefore we zero initialise everything, and hope >+ // that LLVM is smart enough to avoid emitting anything if it doesn't need to. >+ private _zeroInitialize(type, variableName, allowComment = true) >+ { >+ const emitter = this; >+ >+ class ZeroInitializer extends Visitor { >+ visitNativeType(node) >+ { >+ if (node.name == "bool") >+ emitter._add(`${variableName} = false;`); >+ else >+ emitter._add(`${variableName} = 0;`); >+ } >+ >+ visitPtrType(node) >+ { >+ emitter._add(`${variableName} = nullptr;`); >+ } >+ >+ visitArrayType(node) >+ { >+ for (let i = 0; i < node.numElements.value; i++) >+ emitter._zeroInitialize(node.elementType, `${variableName}[${i}]`, false); >+ } >+ >+ visitArrayRefType(node) >+ { >+ emitter._add(`${variableName}.ptr = nullptr;`); >+ emitter._add(`${variableName}.length = 0;`); >+ } >+ >+ visitEnumType(node) >+ { >+ emitter._zeroInitialize(node.baseType, variableName, false); >+ } >+ >+ visitStructType(node) >+ { >+ const typeAttributes = emitter._typeAttributes.attributesForType(node); >+ const typeIsNative = emitter._typeNamer.typeUnifier._structIsNative(node); >+ >+ for (let field of node.fields) { >+ let fieldName = field.name; >+ if (typeAttributes && !typeIsNative) >+ fieldName = typeAttributes.mangledFieldName(fieldName); >+ emitter._zeroInitialize(field.type, `${variableName}.${fieldName}`, false); >+ } >+ } >+ } >+ if (allowComment) >+ this._add(`// Zero initialization of ${variableName}`); >+ Node.visit(type, new ZeroInitializer()); >+ } >+ >+ get actualResult() >+ { >+ return this._actualResult; >+ } >+ >+ get lines() >+ { >+ return this._lines; >+ } >+ >+ indentedSource() >+ { >+ return this._lines.map(line => " " + line + "\n").join(""); >+ } >+ >+ private get _loopConditionVariable(): string >+ { >+ return this._loopConditionVariableStack[this._loopConditionVariableStack.length - 1]; >+ } >+ >+ private get _loopCondition(): Node >+ { >+ return this._loopConditionNodeStack[this._loopConditionNodeStack.length - 1]; >+ } >+ >+ private get _loopIncrement(): Node >+ { >+ return this._loopIncrementNodeStack[this._loopIncrementNodeStack.length - 1]; >+ } >+ >+ private _add(linesString) >+ { >+ for (let line of linesString.split('\n')) { >+ for (let i = 0; i < this._indentLevel; i++) >+ line = " " + line; >+ this._lines.push(line); >+ } >+ } >+ >+ private _addLines(lines) >+ { >+ for (let line of lines) >+ this._add(line); >+ } >+ >+ private _fresh() >+ { >+ return this._counter.fresh(); >+ } >+ >+ private _indent() >+ { >+ this._indentLevel++; >+ } >+ >+ private _unindent() >+ { >+ this._indentLevel--; >+ } >+ >+ // Atomic statements. >+ >+ visitBreak(node) >+ { >+ this._add("break;") >+ } >+ >+ visitContinue(node) >+ { >+ // This is necessary because for loops are compiled as while loops, so we need to do >+ // the loop increment and condition check before returning to the beginning of the loop. >+ this._emitLoopBodyEnd(); >+ this._add("continue;"); >+ } >+ >+ // Basic compound statements. >+ >+ visitBlock(block) >+ { >+ this._nameMapStack.push(this._nameMap); >+ this._nameMap = new Map(this._nameMap); >+ for (let stmt of block.statements) { >+ if (stmt.origin && stmt.origin.index && this._lineNumbers && this._lineNumbers[stmt.origin.index]) >+ this._add(`// ${this._debugName} @ line ${this._lineNumbers[stmt.origin.index]}`); >+ Node.visit(stmt, this); >+ } >+ this._nameMap = this._nameMapStack.pop(); >+ } >+ >+ visitReturn(node) >+ { >+ let expr = node.value.visit(this); >+ if (this._resultVar) >+ this._add(`${this._resultVar} = ${expr};`); >+ else >+ this._add(`return ${expr};`); >+ } >+ >+ private _inScope(emitBraces = false, emitBlock: () => any) >+ { >+ if (emitBraces) >+ this._add("{"); >+ this._indent(); >+ >+ this._nameMapStack.push(this._nameMap); >+ this._nameMap = new Map(this._nameMap); >+ >+ const res = emitBlock(); >+ >+ this._nameMap = this._nameMapStack.pop(); >+ if (emitBraces) >+ this._add("}"); >+ >+ this._unindent(); >+ >+ return res; >+ } >+ >+ private _emitScoped(node: Node, emitBraces = false) >+ { >+ if (!node) >+ throw new Error(`Can't emit scoped null node`); >+ >+ return this._inScope(emitBraces, () => Node.visit(node, this)); >+ } >+ >+ visitIfStatement(node) >+ { >+ let condition = node.conditional.visit(this); >+ this._add(`if (${condition}) {`); >+ this._emitScoped(node.body); >+ // At the moment the parser emits Block nodes for the if and else bodies, so this allows us >+ // to check whether or not the else body is actually empty, and therefore doesn't need to be emitted. >+ // (This isn't necessary, it just yields shorter, easier to read output). >+ const shouldEmitElseBody = node.elseBody && (!(node.elseBody instanceof Block) || node.elseBody.statements.length); >+ if (shouldEmitElseBody) { >+ this._add(`} else {`); >+ this._emitScoped(node.elseBody); >+ this._add('}'); >+ } else >+ this._add('}'); >+ } >+ >+ visitIdentityExpression(node) >+ { >+ return node.target.visit(this); >+ } >+ >+ visitLogicalNot(node) >+ { >+ const type = typeOf(node); >+ if (type) { >+ let expr = Node.visit(node.operand, this); >+ let id = this._fresh(); >+ this._add(`${this._typeNamer.mslTypeName(type)} ${id} = !(${expr});`); >+ return id; >+ } else >+ throw new Error(`Couldn't determine type of ! expression ${node}'`); >+ } >+ >+ visitDereferenceExpression(node) >+ { >+ /* >+ An assignment such as someStruct.field = someValue is parsed as >+ *((&someStruct)->value) = someValue >+ which isn't ideal, because we can't take the address of a member like .x/.y/.z in a SIMD type. >+ Therefore to avoid this pattern we determine if the expression we are dereferencing is >+ just producing a reference, because then we can avoid both steps. >+ */ >+ if (this._canAvoidDereferenceBecauseDereferencingReferenceNode(node.ptr)) >+ return this._doNotProduceReferenceFromReferenceNode(node.ptr); >+ else { >+ let result = node.ptr.visit(this); >+ return `*(${result})`; >+ } >+ } >+ >+ private _canAvoidDereferenceBecauseDereferencingReferenceNode(node) >+ { >+ const emitter = this; >+ >+ class PossibleRefVisitor extends Visitor { >+ visitMakePtrExpression(node) { return true; } >+ >+ visitCallExpression(node) >+ { >+ return emitter._isOperatorAnder(node) || emitter._isOperatorIndexer(node); >+ } >+ } >+ >+ // To avoid returning undefined/issues with functions not being defined. >+ return Node.visit(node, new PossibleRefVisitor()) ? true : false; >+ } >+ >+ private _isOperatorAnder(node) >+ { >+ const anderRegex = /^operator\&\.(.*?)$/; >+ return node.nativeFuncInstance && anderRegex.test(node.nativeFuncInstance.name); >+ } >+ >+ private _isOperatorGetter(node) >+ { >+ const getterRegex = /^operator.\.(.*?)$/; >+ return node.nativeFuncInstance && getterRegex.test(node.nativeFuncInstance.name); >+ } >+ >+ private _isOperatorIndexer(node) >+ { >+ return node.nativeFuncInstance && node.nativeFuncInstance.name == "operator&[]"; >+ } >+ >+ private _isOperatorSetter(node) >+ { >+ const setterRegex = /^operator\.(.*?)=$/; >+ return node.nativeFuncInstance && setterRegex.test(node.nativeFuncInstance.name) >+ } >+ >+ private _isOperatorVectorAccessor(node) >+ { >+ const regex = /^operator\.[xyzw]+$/g; >+ return node.func && node.func.implementationData instanceof SwizzleOp && regex.test(node.func.name); >+ } >+ >+ private _isOperatorCast(node: Func) >+ { >+ return node instanceof NativeFuncInstance && node.name == "operator cast"; >+ } >+ >+ private _isUnaryOperator(node) >+ { >+ const operatorRegex = /^operator\~$/; >+ console.log(node); >+ return node.func && operatorRegex.test(node.name); >+ } >+ >+ private _isBinaryOperator(node) >+ { >+ const operatorRegex = /operator(\+|\-|\*|\/|\^|\&|\||\&\&|\|\||\<\<|\>\>|\<|\<\=|\>|\>\=|\=\=|\!\=)$/; >+ return node.func && operatorRegex.test(node.name); >+ } >+ >+ private _extractOperatorName(node) >+ { >+ return node.name.substring("operator".length); >+ } >+ >+ private _doNotProduceReferenceFromReferenceNode(node) >+ { >+ const emitter = this; >+ >+ class DefiniteRefVisitor extends Visitor { >+ >+ visitMakePtrExpression(node) >+ { >+ return Node.visit(node.lValue, emitter); >+ } >+ >+ visitCallExpression(node) >+ { >+ const anderRegex = /^operator\&\.(.*?)$/; >+ if (anderRegex.test(node.nativeFuncInstance.name)) >+ return emitter._handleFieldAccess(node); >+ else if (node.nativeFuncInstance.name === "operator&[]") >+ return emitter._handleIndexAccess(node); >+ } >+ } >+ >+ return Node.visit(node, new DefiniteRefVisitor()); >+ } >+ >+ visitVariableDecl(node) >+ { >+ let id = this._fresh(); >+ this._nameMap.set(node.name, id); >+ >+ this._add(`${new VarOrFieldDeclaration(this._typeNamer, node.type, id)}; // ${node.name}`); >+ >+ if (node.initializer) { >+ let expr = node.initializer.visit(this); >+ this._add(`${id} = ${expr};`); >+ } else >+ this._zeroInitialize(node.type, id); >+ } >+ >+ visitVariableRef(node) >+ { >+ if (node.variable instanceof AnonymousVariable) >+ return Node.visit(node.variable, this); >+ let name = node.name; >+ if (!this._nameMap.has(name)) >+ throw new Error(`${node.name} not found in this function's variable map`); >+ return this._nameMap.get(name); >+ } >+ >+ visitMakeArrayRefExpression(node) >+ { >+ const elemName = Node.visit(node.lValue, this); >+ const type = this._typeNamer.mslTypeName(node.type); >+ const id = this._fresh(); >+ this._add(`${type} ${id};`); >+ this._add(`${id}.length = ${node.numElements.value};`); >+ this._add(`${id}.ptr = ${elemName};`); >+ return id; >+ } >+ >+ visitAnonymousVariable(node) >+ { >+ // Anonymous variable names are of the form anonVar<i> (where i is an integer), i.e. >+ // the set of anonymous variable names is disjoint from the set of definable variable names. >+ if (!this._nameMap.has(node.name)) { >+ let id = this._fresh(); >+ this._nameMap.set(node.name, id); >+ this._add(`${this._typeNamer.mslTypeName(node.type)} ${id}; // ${node.name}`); >+ this._zeroInitialize(node.type, id); >+ return id; >+ } else >+ return this._nameMap.get(node.name); >+ } >+ >+ visitAssignment(node) >+ { >+ const lhs = Node.visit(node.lhs, this); >+ const rhs = Node.visit(node.rhs, this); >+ this._add(`${lhs} = ${rhs};`); >+ return rhs; >+ } >+ >+ visitCommaExpression(node: CommaExpression) >+ { >+ let result; >+ for (let expr of node.list) >+ result = Node.visit(expr, this); >+ return result; >+ } >+ >+ visitCallExpression(node) >+ { >+ // Evaluate the arguments right-to-left. >+ let argIds = []; >+ for (let i = node.argumentList.length - 1; i >= 0; i--) { >+ let id = node.argumentList[i].visit(this); >+ argIds.unshift(id); >+ } >+ let result = this._fresh(); >+ if (node.func.returnType.name !== "void") { >+ this._add(`// Result variable for call ${node.func.name}(${argIds.join(", ")})`); >+ this._add(`${this._typeNamer.mslTypeName(node.resultType)} ${result};`); >+ } >+ this._makeFunctionCall(node.nativeFuncInstance, result, argIds); >+ >+ return result; >+ } >+ >+ private _makeFunctionCall(node, result, args) >+ { >+ if (!node) >+ throw new Error(`Can't compile call ${node} of non-native functions'`); >+ >+ if (this._isOperatorVectorAccessor(node)) >+ this._add(`${result} = ${args[0]}.${node.func.implementationData.components.join("")};`); >+ else if (this._isOperatorAnder(node)) { >+ this._add(`// ${node.name}`); >+ this._add(`${result} = &(${this._handleFieldAccess(node)});`); >+ } else if (this._isOperatorSetter(node)) >+ this._add(`// TODO: (Native function) ${node.name}`); >+ else if (this._isOperatorGetter(node)) >+ this._add(`// TODO: (Native function) ${node.name}`); >+ else if (this._isOperatorIndexer(node)) >+ this._add(`// TODO: (Native function) ${node.name}`); >+ else if (this._isOperatorCast(node)) { >+ const retType = this._typeNamer.mslTypeName(node.returnType); >+ this._add(`${result} = ${retType}(${args.join(", ")});`); >+ } else if (this._isUnaryOperator(node)) { >+ const op = this._extractOperatorName(node); >+ this._add(`${result} = ${op}(${args[0]});`); >+ } else if (this._isBinaryOperator(node)) { >+ const op = this._extractOperatorName(node); >+ this._add(`${result} = ${args[0]} ${op} ${args[1]};`); >+ } else if (node.name == "log" || node.name == "pow" || node.name == "sin" || node.name == "cos" || node.name == "atan2") >+ this._emitCallToMetalFunction(node.name, result, args); >+ else >+ throw new Error(`Unimplemented native function '${node.name}' at MSLStatementEmitter.makeFunctionCall`); >+ >+ return result; >+ } >+ >+ private _emitCallToMetalFunction(name, result, args) >+ { >+ this._add(`${result} = ${name}(${args.join(", ")});`); >+ } >+ >+ private _handleFieldAccess(node) >+ { >+ const arg = node.argumentList[0]; >+ let field = node.nativeFuncInstance.implementationData.fieldName; >+ const type = node.nativeFuncInstance.implementationData.type; >+ const typeAttributes = this._typeAttributes.attributesForType(type); >+ const typeIsNative = this._typeNamer.typeUnifier._structIsNative(type); >+ if (typeAttributes && !typeIsNative) >+ field = typeAttributes.mangledFieldName(field); >+ >+ if (arg instanceof MakePtrExpression) { >+ const argId = Node.visit(arg.lValue, this); >+ if (arg.lValue && arg.lValue instanceof VariableRef) >+ return `${argId}.${field}`; >+ else >+ return `(${argId}).${field}`; >+ } else >+ return `${Node.visit(arg, this)}->${field}`; >+ } >+ >+ private _handleIndexAccess(node) >+ { >+ const array = node.argumentList[0]; >+ const index = node.argumentList[1]; >+ >+ if (array instanceof MakeArrayRefExpression) { >+ if (index.isLiteral) { >+ // Type checking will hopefully have already ensured this... >+ if (index.value >= 0 && index.value < array.numElements.value) { >+ const variable = Node.visit(array.lValue, this); >+ return `${variable}[${index.value}]`; >+ } else >+ throw new Error(`Index out of bounds in ${node}`); >+ } else { >+ // TODO: It would be interesting to see what kind of BCE could be done here. >+ // Index checks aren't necessary for values < 0 because the type checker will >+ // have already ensured that the index value type is an unsigned integer. >+ const variable = Node.visit(array.lValue, this); >+ const indexId = Node.visit(index, this); >+ this._add(`if (${indexId} >= ${array.numElements.value}) {`); >+ this._indent(); >+ this._emitReturnZeroValue(); >+ this._unindent(); >+ this._add(`}`); >+ return `${variable}[${indexId}]`; >+ } >+ } else >+ this._add(`// TODO: Handle ${array} in MSLStatementEmitter._handleIndexAccess`); >+ } >+ >+ visitMakePtrExpression(node) >+ { >+ const expr = node.lValue.visit(this); >+ return `&(${expr})`; >+ } >+ >+ visitFunctionLikeBlock(node) >+ { >+ const canBeInlined = functionLikeBlockCanBeInlined(node); >+ if (canBeInlined) >+ this._add(`// inline ${node.origin.text}`); >+ else >+ this._add(`// call to ${node.origin.text}`); >+ >+ // 1. Create result variable if necessary. >+ let resultVar = null; >+ if (node.returnType.name != "void") { >+ resultVar = this._fresh(); >+ this._add(`${this._typeNamer.mslTypeName(node.returnType)} ${resultVar};`); >+ } >+ >+ this._add("{"); >+ this._indent(); >+ >+ // 2. Evaluate the arguments. >+ const args = []; >+ for (let i = node.argumentList.length - 1; i >= 0; i--) { >+ let id = node.argumentList[i].visit(this); >+ args.unshift(id); >+ } >+ >+ // 3. Emit the call inline or as a real call. >+ if (canBeInlined) >+ this._callFunctionLikeBlockInline(node, resultVar, args); >+ else >+ this._callFunctionLikeBlockWithCall(node, resultVar, args); >+ >+ this._unindent(); >+ this._add("}"); >+ >+ return resultVar; >+ } >+ >+ private _callFunctionLikeBlockInline(node, resultVar, args) >+ { >+ const nameMap = new Map(this._nameMap); >+ const params = node.parameters; >+ for (let i = 0; i < params.length; i++) >+ nameMap.set(params[i].name, args[i]); >+ >+ const emitter = new MSLStatementEmitter(this._funcMangler, this._typeNamer, node.body, nameMap, node.origin.text, this._lineNumbers, this._typeAttributes, resultVar, this._counter, this.ancestorReturnType); >+ this._addLines(emitter.lines); >+ } >+ >+ private _callFunctionLikeBlockWithCall(node, resultVar, args) >+ { >+ const mangledCallName = this._funcMangler.mangle(node.func); >+ this._add(`${resultVar} = ${mangledCallName}(${args.join(", ")});`); >+ } >+ >+ // Loop code generation. Loops all follow the same style where they declare a conditional variable (boolean) >+ // which is checked on each iteration (all loops are compiled to a while loop or do/while loop). The check is >+ // emitted in _emitLoopCondition. For loops additionally have _emitLoopBodyEnd for the increment on each iteration. >+ >+ visitForLoop(node: ForLoop) >+ { >+ this._emitAsLoop(node.condition, node.increment, (conditionVar) => { >+ Node.visit(node.initialization, this); >+ this._emitLoopCondition(); >+ this._add(`while (${conditionVar}) {`); >+ this._emitScoped(node.body); >+ this._emitLoopBodyEnd(); >+ this._add('}'); >+ }); >+ } >+ >+ visitWhileLoop(node) >+ { >+ this._emitAsLoop(node.conditional, null, (conditionVar) => { >+ this._add(`while (${conditionVar}) {`); >+ this._emitScoped(node.body); >+ this._emitLoopCondition(); >+ this._add('}'); >+ }); >+ } >+ >+ visitDoWhileLoop(node) >+ { >+ this._emitAsLoop(node.conditional, null, (conditionVar: string) => { >+ this._add("do {"); >+ this._emitScoped(node.body); >+ this._emitLoopBodyEnd(); >+ this._add(`} while (${conditionVar});`); >+ }); >+ } >+ >+ private _emitAsLoop(conditional: Node, increment: Node, emitLoopBody: (conditionalVar: string) => void) >+ { >+ const conditionVar = this._fresh(); >+ this._loopConditionVariableStack.push(conditionVar); >+ this._loopConditionNodeStack.push(conditional); >+ this._loopIncrementNodeStack.push(increment); >+ this._add(`bool ${conditionVar} = true;`); >+ >+ emitLoopBody(conditionVar); >+ >+ this._loopIncrementNodeStack.pop(); >+ this._loopConditionVariableStack.pop(); >+ this._loopConditionNodeStack.pop(); >+ } >+ >+ private _emitLoopBodyEnd() >+ { >+ this._emitLoopIncrement(); >+ this._emitLoopCondition(); >+ } >+ >+ private _emitLoopIncrement() >+ { >+ if (this._loopIncrement) >+ this._emitScoped(this._loopIncrement); >+ } >+ >+ private _emitLoopCondition() >+ { >+ if (this._loopCondition) { >+ const conditionResult: Node = this._emitScoped(this._loopCondition); >+ this._add(`${this._loopConditionVariable} = ${conditionResult};`); >+ } >+ } >+ >+ // Switch statements. >+ >+ visitSwitchStatement(node) >+ { >+ const caseValueEmitter = new ConstexprEmitter(); >+ >+ let switchValue = Node.visit(node.value, this); >+ this._add(`switch (${switchValue}) {`); >+ this._indent(); >+ >+ for (let i = 0; i < node.switchCases.length; i++) { >+ let switchCase = node.switchCases[i]; >+ if (!switchCase.isDefault) >+ this._add(`case ${Node.visit(switchCase.value, caseValueEmitter)}: {`); >+ else >+ this._add("default: {"); >+ this._emitScoped(switchCase.body); >+ this._add("}"); >+ } >+ >+ this._unindent(); >+ this._add("}"); >+ } >+ >+ visitSwitchCase(node) >+ { >+ throw new Error(`// FIXME: Hit |visitSwitchCase|, should be handled by |visitSwitchStatement|`); >+ } >+ >+ // Literals >+ >+ visitBoolLiteral(node) >+ { >+ const fresh = this._fresh(); >+ this._add(`bool ${fresh} = ${node.value};`); >+ return fresh; >+ } >+ >+ visitEnumLiteral(node) >+ { >+ const fresh = this._fresh(); >+ this._add(`${this._typeNamer.mslTypeName(node.type.baseType)} ${fresh} = ${node.member.value};`); >+ return fresh; >+ } >+ >+ visitGenericLiteral(node) >+ { >+ const fresh = this._fresh(); >+ this._add(`${this._typeNamer.mslTypeName(node.type)} ${fresh} = ${node.value};`); >+ return fresh; >+ } >+ >+ visitNullLiteral(node) >+ { >+ return `(nullptr)`; >+ } >+ >+ visitDotExpression(node) >+ { >+ throw new Error(`Dot expressions ${node} should have been converted to an operator`); >+ } >+ >+ visitTrapStatement(node) >+ { >+ this._emitReturnZeroValue(); >+ } >+ >+ // Unimplemented methods. I write out comments for these rather than throwing exceptions because it makes it easier for me >+ // to see where the nodes occur in the abstract syntax tree >+ >+ visitConvertPtrToArrayRefExpression(node) >+ { >+ this._add("// TODO: visitConvertPtrToArrayRefExpression"); >+ } >+ >+ visitIndexExpression(node) >+ { >+ this._add("// TODO: visitIndexExpression"); >+ } >+ >+ visitLogicalExpression(node) >+ { >+ this._add("// TODO: visitLogicalExpression"); >+ } >+ >+ visitNativeFunc(node) >+ { >+ this._add("// TODO: visitNativeFunc"); >+ } >+ >+ visitNativeFuncInstance(node) >+ { >+ this._add("// TODO: visitNativeFuncInstance"); >+ } >+ >+ visitNativeTypeInstance(node) >+ { >+ this._add("// TODO: visitNativeTypeInstance"); >+ } >+ >+ visitReadModifyWriteExpression(node) >+ { >+ this._add("// TODO: visitReadModifyWriteExpression"); >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeNamer.ts b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeNamer.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..65996f954e6867cda121b844b40d1d1e25ddae8c >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MSLTypeNamer.ts >@@ -0,0 +1,114 @@ >+/* >+ * 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. >+ */ >+ >+class MSLTypeNamer { >+ private _typeUnifier: TypeUnifier; >+ >+ constructor(typeUnifier) >+ { >+ this._typeUnifier = typeUnifier; >+ } >+ >+ get typeUnifier() >+ { >+ return this._typeUnifier; >+ } >+ >+ uniqueTypeId(type) >+ { >+ return this.typeUnifier.uniqueTypeId(type); >+ } >+ >+ // Yields the string that should be used in MSL source for the type. >+ mslTypeName(type) >+ { >+ let name = ""; >+ >+ const unifiedType = this.typeUnifier.unifyTypes(type); >+ const typeUnifier = this.typeUnifier; >+ const typeNamer = this; >+ >+ class TypeNameVisitor extends Visitor >+ { >+ visitNativeType(node) >+ { >+ const nativeTypeNameMap = { >+ "void": "void", >+ "uint8": "uchar", >+ "int32": "int", >+ "uint32": "uint", >+ "bool": "bool", >+ "float32": "float", >+ // Metal does not natively support double. >+ // It is possibly to use it with -fnative-double as a Metal compiler flag. >+ // FIXME: Review whether we can set the flag in runtime compilation. >+ "float64": "double" >+ }; >+ >+ name = nativeTypeNameMap[node.name]; >+ } >+ >+ visitStructType(node) >+ { >+ if (typeUnifier._structIsNative(node)) { >+ let suffix = ""; >+ if (node.name == "vec2") >+ suffix = "2"; >+ else if (node.name == "vec3") >+ suffix = "3"; >+ else if (node.name == "vec4") >+ suffix = "4"; >+ >+ name = typeNamer.mslTypeName(node.fields.next().value.type) + suffix; >+ } else >+ name = typeUnifier.uniqueTypeId(node); >+ } >+ >+ visitEnumType(node) >+ { >+ return Node.visit(node.baseType, this); >+ } >+ >+ visitReferenceType(node) >+ { >+ name = `${node.addressSpace} ${typeNamer.mslTypeName(node.elementType)}*`; >+ } >+ >+ visitArrayType(node) >+ { >+ name = `${typeNamer.mslTypeName(node.elementType)}*`; >+ } >+ >+ visitArrayRefType(node) >+ { >+ name = typeUnifier.uniqueTypeId(node); >+ } >+ } >+ >+ unifiedType.visit(new TypeNameVisitor()); >+ >+ return name; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/MetalCodegen.ts b/Tools/WebGPUShadingLanguageRI/Metal/MetalCodegen.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..3a489be2e50ec9ee40b6adb5c680770a1590871c >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/MetalCodegen.ts >@@ -0,0 +1,293 @@ >+/* >+ * 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. >+ */ >+ >+const DefaultMetalSource = `#include <metal_stdlib> >+using namespace metal; >+ >+`; >+ >+// Handles the compilation of Program AST instances to CompileResult instances, which >+// include the raw MSL. In general clients should call |whlslToMsl|, which parses, >+// typechecks, and inlines the WHLSL before passing it to this compiler. >+class MetalCodegen { >+ private _program: Program; >+ private _lineNumbers: number[]; >+ private _declarations: any[]; >+ private _allowComments: boolean; >+ private _includeFunctionForwardDeclarations: boolean; >+ private _includeTypeReference: boolean; >+ private _typeUnifier: TypeUnifier; >+ private _typeNamer: MSLTypeNamer; >+ private _forwardTypeDecls: any[]; >+ private _typeDefinitions: any[]; >+ private _forwardFunctionDecls: any[]; >+ private _functionDefintions: MSLFunctionDefinition[]; >+ private _allTypeAttributes: FindTopLevelTypeAttributes; >+ private _funcNameMangler: NameMangler; >+ private _functionSources: Map<string, string>; >+ >+ constructor(program: Program, lineNos: number[] = null) >+ { >+ this._program = program; >+ this._lineNumbers = lineNos; >+ >+ this._declarations = []; >+ >+ this._allowComments = true; >+ this._includeFunctionForwardDeclarations = true; >+ this._includeTypeReference = true; >+ } >+ >+ get program() >+ { >+ return this._program; >+ } >+ >+ get declarations() >+ { >+ return this._declarations; >+ } >+ >+ get allowComments() >+ { >+ return this._allowComments; >+ } >+ >+ set allowComments(newAllowComments) >+ { >+ this._allowComments = newAllowComments; >+ } >+ >+ get includeTypeReference() >+ { >+ return this._includeTypeReference; >+ } >+ >+ set includeTypeReference(newValue) >+ { >+ this._includeTypeReference = newValue; >+ } >+ >+ get functionSources(): Map<string, string> >+ { >+ return this._functionSources; >+ } >+ >+ // The main entry point for the compiler, however clients should generally call whlslToMsl, >+ // which is defined at the bottom of this file. >+ generateMsl(): CompileResult >+ { >+ try { >+ const src = this._tryGenerateMsl(); >+ const mangledMap = {}; >+ for (let func of this._functionDefintions) { >+ const key = func.func.name; >+ const value = func.mangledName; >+ if (!(key in mangledMap)) >+ mangledMap[key] = []; >+ mangledMap[key].push(value); >+ } >+ >+ return new CompileResult(src, null, mangledMap, this._functionSources); >+ } catch (e) { >+ return new CompileResult(null, e, null, null); >+ } >+ } >+ >+ private _tryGenerateMsl(): string >+ { >+ this._typeUnifier = new TypeUnifier(); >+ this._typeNamer = new MSLTypeNamer(this._typeUnifier); >+ this._forwardTypeDecls = []; >+ this._typeDefinitions = []; >+ this._forwardFunctionDecls = []; >+ this._functionDefintions = []; >+ >+ // Step 1: Find all the functions that actually need to be compiled >+ // (including functions that need to be de-inlined). We additionally perform >+ // type unification. >+ >+ const entryFuncDefs = this._findEntryPointDefinitions(); >+ const unifiedEntryFunctionDefs = this._unifyFunctionTypes(entryFuncDefs); >+ const unifiedFunctionDefs = this._findFunctionDefinitionsToCompile(unifiedEntryFunctionDefs); >+ >+ // Step 2: Find properties of the types and create type and function declarations. >+ >+ this._allTypeAttributes = new FindTopLevelTypeAttributes(unifiedFunctionDefs, this._typeUnifier); >+ this._createTypeDecls(); >+ this._createFunctionDecls(unifiedFunctionDefs); >+ >+ // Step 3: Generate the actual MSL source code. >+ >+ let outputStr = DefaultMetalSource; >+ >+ const addSection = (title, decls) => { >+ outputStr += `#pragma mark - ${title}\n\n${decls.join("\n\n")}\n\n`; >+ }; >+ >+ addSection("Forward type declarations", this._forwardTypeDecls); >+ addSection("Type definitions", this._typeDefinitions); >+ if (this._includeFunctionForwardDeclarations) >+ addSection("Forward function declarations", this._forwardFunctionDecls); >+ addSection("Function definitions", this._functionDefintions); >+ >+ // Step 4: Post-generation source tidy up (type reference comments and comment removal). >+ >+ if (this.includeTypeReference) { >+ outputStr += "#pragma mark - Type reference\n"; >+ for (let type of this._typeUnifier.allTypes) { >+ const typeId = this._typeUnifier.uniqueTypeId(type); >+ const typeName = this._typeUnifier.uniqueName(type); >+ outputStr += `\n// ${typeId} <- ${typeName}`; >+ } >+ } >+ >+ if (!this.allowComments) >+ outputStr = this._removeCommentsAndEmptyLines(outputStr); >+ >+ // Step 5: Create a map of the mangled function names to their source >+ // (used for the copy buttons). >+ this._functionSources = new Map(); >+ for (let func of this._functionDefintions) >+ this._functionSources.set(func.mangledName, func.toString()); >+ >+ return outputStr; >+ } >+ >+ private _findEntryPointDefinitions() >+ { >+ const functions = []; >+ for (let instances of this._program.funcInstantiator.instances.values()) { >+ for (let instance of instances) { >+ if (instance.func.isEntryPoint) >+ functions.push(instance); >+ } >+ } >+ return functions; >+ } >+ >+ private _unifyFunctionTypes(functionDefinitions) >+ { >+ this._funcNameMangler = new NameMangler('F'); >+ return functionDefinitions.map((f, i) => { >+ const unifiedFunc = this._typeUnifier.unifyTypes(f.func); >+ return { >+ func: unifiedFunc, >+ typeArguments: f.typeArguments.map(arg => this._typeUnifier.unifyTypes(arg)), >+ mangledName: this._funcNameMangler.mangle(unifiedFunc) >+ } >+ }); >+ } >+ >+ // Finds FunctionLikeBlocks that can't be inlined because they don't have reducible control flow, so promotes them >+ // to full function definitions. >+ private _findFunctionDefinitionsToCompile(functionDefinitions) >+ { >+ const functionSet = new Set<Node>(); >+ const funcNameMangler = this._funcNameMangler; >+ >+ class FindFunctionsToDeclare extends Visitor { >+ visitFunctionLikeBlock(node: FunctionLikeBlock) >+ { >+ if (!functionSet.has(node.func)) { >+ if (!functionLikeBlockCanBeInlined(node)) { >+ functionSet.add(node.func); >+ functionDefinitions.push({ >+ func: node.func, >+ typeArguments: [], >+ mangledName: funcNameMangler.mangle(node.func) >+ }); >+ } >+ super.visitFunctionLikeBlock(node); >+ } >+ } >+ } >+ >+ const visitor = new FindFunctionsToDeclare(); >+ >+ for (let funcDef of functionDefinitions) >+ Node.visit(funcDef.func, visitor); >+ >+ return functionDefinitions; >+ } >+ >+ private _createTypeDecls() >+ { >+ const typesThatNeedDeclaration = this._typeUnifier.typesThatNeedDeclaration(); >+ const typeDeclsInOrder = this._sortTypeDeclarationsInTopologicalOrder(typesThatNeedDeclaration); >+ >+ for (let type of typeDeclsInOrder) { >+ const metalStructCodeGen = new StructCodegen(type, this._typeNamer, this._lineNumbers, this._allTypeAttributes.attributesForType(type)); >+ this._forwardTypeDecls.push(metalStructCodeGen.forwardDeclaration); >+ this._typeDefinitions.push(metalStructCodeGen.finalDefinition); >+ } >+ } >+ >+ private _createFunctionDecls(unifiedFunctionDefs) >+ { >+ for (let func of unifiedFunctionDefs) { >+ this._forwardFunctionDecls.push(new MSLFunctionForwardDeclaration(this._funcNameMangler, func.func, func.typeArguments, this._typeNamer, func.mangledName, this._lineNumbers, this._allTypeAttributes)); >+ this._functionDefintions.push(new MSLFunctionDefinition(this._funcNameMangler, func.func, func.typeArguments, this._typeNamer, func.mangledName, this._lineNumbers, this._allTypeAttributes)); >+ } >+ } >+ >+ private _sortTypeDeclarationsInTopologicalOrder(typesToDeclare) >+ { >+ const declarations = new Array(); >+ for (let type of typesToDeclare) >+ declarations.push(type); >+ const typeOrder = new TypeSorter(this._typeUnifier, typesToDeclare).topologicalOrder; >+ const typeOrderMap = new Map<Type, number>(); >+ for (let i = 0; i < typeOrder.length; i++) >+ typeOrderMap.set(typeOrder[i], i); >+ return declarations.sort((a, b) => typeOrderMap.get(this._typeUnifier.uniqueTypeId(a)) - typeOrderMap.get(this._typeUnifier.uniqueTypeId(b))); >+ } >+ >+ // Also removes #pragma marks. >+ private _removeCommentsAndEmptyLines(src) >+ { >+ const singleLineCommentRegex = /(\/\/|\#pragma)(.*?)($|\n)/; >+ const lines = src.split('\n') >+ .map(line => line.replace(singleLineCommentRegex, '').trimEnd()) >+ .filter(line => line.length > 0); >+ return lines.join('\n'); >+ } >+} >+ >+// Main wrapper for the compiler. Clients should use this function to compile WHLSL. >+function whlslToMsl(src: string): CompileResult { >+ let parsedProgram; >+ try { >+ parsedProgram = prepare("/internal/test", 0, src); >+ } catch (e) { >+ return new CompileResult(null, e, null, null); >+ } >+ >+ if (!(parsedProgram instanceof Program)) >+ return new CompileResult(null, new Error("Compilation failed"), null, null); >+ >+ const compiler = new MetalCodegen(parsedProgram, lineNumbers(src)); >+ return compiler.generateMsl(); >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/NameMangler.ts b/Tools/WebGPUShadingLanguageRI/Metal/NameMangler.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..6f017197d7aea8fcf47503cb4a5b4daa9ca8def0 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/NameMangler.ts >@@ -0,0 +1,45 @@ >+/* >+ * 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. >+ */ >+ >+class NameMangler { >+ private _prefix: string; >+ private _counter: number; >+ private _mangledNameMap: Map<any, string>; >+ >+ constructor(prefix: string) >+ { >+ this._prefix = prefix; >+ this._counter = 0; >+ this._mangledNameMap = new Map(); >+ } >+ >+ mangle(key: any): string >+ { >+ if (!this._mangledNameMap.has(key)) { >+ this._mangledNameMap.set(key, `${this._prefix}${this._counter++}`); >+ } >+ return this._mangledNameMap.get(key); >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/README.md b/Tools/WebGPUShadingLanguageRI/Metal/README.md >new file mode 100644 >index 0000000000000000000000000000000000000000..97cd86451de65695ad5b3b56338a81b721145093 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/README.md >@@ -0,0 +1,16 @@ >+# Metal Shader Language code generation >+ >+## Building >+ >+The MSL compiler is based around the existing WSL interpreter in the parent directory. The compiler is written in TypeScript, a typed superset of JavaScript. To compile and run the compiler: >+ >+1. Install [Node.js][Node] LTS >+2. Install [TypeScript][typescript] by running `npm install -g typescript` >+3. Either: >+ (a) Open Visual Studio Code, press CMD + SHIFT + B, click `build` or `watch` >+ (b) Run `tsc -p tsconfig.js` inside this directory >+4. Start a web browser in the parent directory >+5. Go to [http://localhost:8000/Metal][] to run the compiler >+ >+[Node]: https://nodejs.org >+[typescript]: https://www.typescriptlang.org >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/StructCodegen.ts b/Tools/WebGPUShadingLanguageRI/Metal/StructCodegen.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..2160084955c8955d0bc34d60780ffb8b5e1b57dc >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/StructCodegen.ts >@@ -0,0 +1,67 @@ >+/* >+ * 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. >+ */ >+ >+class StructCodegen extends Visitor { >+ private _node: StructType; >+ private _typeNamer: MSLTypeNamer; >+ private _lineNumbers: number[]; >+ private _typeAttributes: TypeAttributes; >+ >+ private _forwardDeclaration: StructForwardDeclaration; >+ private _finalDefinition: StructFinalDefinition | ArrayRefDefinition; >+ >+ constructor(node: StructType, typeNamer, lineNos, typeAttributes) >+ { >+ super(); >+ this._node = node; >+ this._typeNamer = typeNamer; >+ this._lineNumbers = lineNos; >+ this._typeAttributes = typeAttributes; >+ >+ Node.visit(node, this); >+ } >+ >+ get forwardDeclaration() >+ { >+ return this._forwardDeclaration; >+ } >+ >+ get finalDefinition() >+ { >+ return this._finalDefinition; >+ } >+ >+ visitStructType(node) >+ { >+ this._forwardDeclaration = new StructForwardDeclaration(node, this._typeNamer, this._lineNumbers); >+ this._finalDefinition = new StructFinalDefinition(node, this._typeNamer, this._lineNumbers, this._typeAttributes); >+ } >+ >+ visitArrayRefType(node) >+ { >+ this._forwardDeclaration = new StructForwardDeclaration(node, this._typeNamer, this._lineNumbers); >+ this._finalDefinition = new ArrayRefDefinition(node, this._typeNamer); >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/StructFinalDefinition.ts b/Tools/WebGPUShadingLanguageRI/Metal/StructFinalDefinition.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..5c834e6c8f4e1778d23fd55d7361ee3aee88a06c >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/StructFinalDefinition.ts >@@ -0,0 +1,87 @@ >+/* >+ * 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. >+ */ >+ >+class StructFinalDefinition { >+ private _structType: StructType; >+ private _typeNamer: MSLTypeNamer; >+ private _lineNumbers: number[]; >+ private _typeAttributes: TypeAttributes; >+ >+ constructor(structType: StructType, typeNamer: MSLTypeNamer, lineNos: number[], typeAttributes: TypeAttributes) >+ { >+ this._structType = structType; >+ this._typeNamer = typeNamer; >+ this._lineNumbers = lineNos; >+ this._typeAttributes = typeAttributes; >+ } >+ >+ get structType() >+ { >+ return this._structType; >+ } >+ >+ toString() >+ { >+ let src = ""; >+ if (this._structType.name) { >+ src += `// ${this._structType.name}`; >+ if (this._lineNumbers && this._structType.origin && this._lineNumbers[this._structType.origin.index]) >+ src += ` @ line ${this._lineNumbers[this._structType.origin.index]}`; >+ src += "\n"; >+ } >+ src += `struct ${this._typeNamer.uniqueTypeId(this._structType)} {\n`; >+ >+ let index = 0; >+ for (let [fieldName,field] of this._structType.fieldMap) { >+ let addAttribute = true; >+ const typeName = this._typeNamer.mslTypeName(field.type); >+ const mangledFieldName = this._typeAttributes.mangledFieldName(fieldName); >+ src += ` ${new VarOrFieldDeclaration(this._typeNamer, field.type, mangledFieldName)}`; >+ >+ const annotations = []; >+ >+ // FIXME: These aren't in the spec yet but are needed for the compiled code to work. >+ if (this._typeAttributes.isVertexAttribute) >+ annotations.push(`attribute(${index++})`); >+ >+ if (this._typeAttributes.isVertexOutputOrFragmentInput && fieldName === "wsl_Position") >+ annotations.push("position"); >+ >+ if (this._typeAttributes.isFragmentOutput && fieldName === "wsl_Color") { >+ // Argument is the color attachment index; we're currently only using 0. >+ annotations.push("color(0)"); >+ } >+ >+ if (annotations.length) >+ src += ` [[${annotations.join(", ")}]]`; >+ >+ src += ";\n"; >+ } >+ >+ src += "};"; >+ >+ return src; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/StructForwardDeclaration.ts b/Tools/WebGPUShadingLanguageRI/Metal/StructForwardDeclaration.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..80a4b7682d9ae249f1ead1e97157dd7f1b7f3f8a >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/StructForwardDeclaration.ts >@@ -0,0 +1,56 @@ >+/* >+ * 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. >+ */ >+ >+class StructForwardDeclaration { >+ private _structType: StructType; >+ private _typeNamer: MSLTypeNamer; >+ private _lineNumbers: number[]; >+ >+ constructor(structType: StructType, typeNamer: MSLTypeNamer, lineNos: number[]) >+ { >+ this._structType = structType; >+ this._typeNamer = typeNamer; >+ this._lineNumbers = lineNos; >+ } >+ >+ get structType() >+ { >+ return this._structType; >+ } >+ >+ toString() >+ { >+ let str = `struct ${this._typeNamer.uniqueTypeId(this._structType)};`; >+ if (this._structType.name) { >+ str += ` // ${this._structType.name}`; >+ if (this._lineNumbers && this._structType.origin && this._lineNumbers[this._structType.origin.index]) >+ str += ` @ line ${this._lineNumbers[this._structType.origin.index]}`; >+ >+ } else >+ str += ` // ${this._structType}`; >+ >+ return str; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/Token.ts b/Tools/WebGPUShadingLanguageRI/Metal/Token.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..f2a364dd4839e8af4d328e5f8058fc6088d1e51c >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/Token.ts >@@ -0,0 +1,58 @@ >+/* >+ * 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. >+ */ >+ >+// The output of MSLLexer. >+class Token { >+ private _type: string; >+ private _src: string; >+ private _startIndex: number; >+ >+ constructor(type, src, start) >+ { >+ this._type = type; >+ this._src = src; >+ this._startIndex = start; >+ } >+ >+ get type(): string >+ { >+ return this._type; >+ } >+ >+ get src(): string >+ { >+ return this._src; >+ } >+ >+ get startIndex(): number >+ { >+ return this._startIndex; >+ } >+ >+ set startIndex(i: number) >+ { >+ this._startIndex = i; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/TypeAttributes.ts b/Tools/WebGPUShadingLanguageRI/Metal/TypeAttributes.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..ebf9df0c0ca0a04b19d4921c28f5e2a4a01d92fe >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/TypeAttributes.ts >@@ -0,0 +1,91 @@ >+/* >+ * 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. >+ */ >+ >+class TypeAttributes { >+ private _type: any; >+ private _isVertexAttribute: boolean; >+ private _isVertexOutputOrFragmentInput: boolean; >+ private _isFragmentOutput: boolean; >+ private _fieldMangler: NameMangler; >+ >+ constructor(type) >+ { >+ this._type = false; >+ this._isVertexAttribute = false; >+ this._isVertexOutputOrFragmentInput = false; >+ this._isFragmentOutput = false; >+ this._fieldMangler = new NameMangler('field'); >+ >+ if (type instanceof StructType) { >+ for (let field of type.fields) >+ this._fieldMangler.mangle(field.name) >+ } >+ } >+ >+ get type() >+ { >+ return this._type; >+ } >+ >+ get isVertexAttribute() >+ { >+ return this._isVertexAttribute; >+ } >+ >+ set isVertexAttribute(va) >+ { >+ this._isVertexAttribute = va; >+ } >+ >+ get isVertexOutputOrFragmentInput() >+ { >+ return this._isVertexOutputOrFragmentInput; >+ } >+ >+ set isVertexOutputOrFragmentInput(vo) >+ { >+ this._isVertexOutputOrFragmentInput = vo; >+ } >+ >+ get isFragmentOutput() >+ { >+ return this._isFragmentOutput; >+ } >+ >+ set isFragmentOutput(fo) >+ { >+ this._isFragmentOutput = fo; >+ } >+ >+ get fieldMangler() >+ { >+ return this._fieldMangler; >+ } >+ >+ mangledFieldName(fieldName) >+ { >+ return this.fieldMangler.mangle(fieldName); >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/TypeOfExpression.ts b/Tools/WebGPUShadingLanguageRI/Metal/TypeOfExpression.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..d6543b558ef096a8fad85a7b533f3020c2e7f08d >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/TypeOfExpression.ts >@@ -0,0 +1,318 @@ >+/* >+ * 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. >+ */ >+ >+function typeOf(node: Node): Type { >+ class TypeVisitor extends Visitor { >+ >+ visitAnonymousVariable(node) >+ { >+ return node.type; >+ } >+ >+ visitArrayRefType(node) >+ { >+ return node; >+ } >+ >+ visitArrayType(node) >+ { >+ return node; >+ } >+ >+ visitAssignment(node) >+ { >+ return node.type; >+ } >+ >+ visitCallExpression(node) >+ { >+ return Node.visit(node.func, this); >+ } >+ >+ visitCommaExpression(node) >+ { >+ return Node.visit(node.list[node.list.length - 1], this); >+ } >+ >+ visitDotExpression(node) >+ { >+ return node.struct.fieldMap.get(node.fieldName).type; >+ } >+ >+ visitElementalType(node) >+ { >+ return node; >+ } >+ >+ visitEnumType(node) >+ { >+ return node; >+ } >+ >+ visitField(node) >+ { >+ return node.type; >+ } >+ >+ visitFunc(node) >+ { >+ return node.returnType; >+ } >+ >+ visitFuncDef(node) >+ { >+ return node.returnType; >+ } >+ >+ visitFuncParameter(node) >+ { >+ return node.type; >+ } >+ >+ visitFunctionLikeBlock(node) >+ { >+ return node.returnType; >+ } >+ >+ visitGenericLiteralType(node) >+ { >+ return node; >+ } >+ >+ visitIdentityExpression(node) >+ { >+ return Node.visit(node.target, this); >+ } >+ >+ visitIndexExpression(node) >+ { >+ return Node.visit(node.array.elementType, this); >+ } >+ >+ visitLogicalExpression(node) >+ { >+ throw new Error("TODO: Implement TypeVisitor.visitLogicalExpression"); >+ } >+ >+ visitLogicalNot(node) >+ { >+ return Node.visit(node.operand, this); >+ } >+ >+ visitMakeArrayRefExpression(node) >+ { >+ return node.type; >+ } >+ >+ visitMakePtrExpression(node) >+ { >+ throw new Error("TODO: Implement TypeVisitor.visitMakePtrExpression"); >+ } >+ >+ visitNativeFunc(node) >+ { >+ return node.returnType; >+ } >+ >+ visitNativeFuncInstance(node) >+ { >+ return node.returnType; >+ } >+ >+ visitNativeType(node) >+ { >+ return node; >+ } >+ >+ visitNativeTypeInstance(node) >+ { >+ return node; >+ } >+ >+ visitNullLiteral(node) >+ { >+ return node.type; >+ } >+ >+ visitNullType(node) >+ { >+ return node; >+ } >+ >+ visitPtrType(node) >+ { >+ return node; >+ } >+ >+ visitReadModifyWriteExpression(node) >+ { >+ throw new Error("TODO: Implement TypeVisitor.visitReadModifyWriteExpression"); >+ } >+ >+ visitReferenceType(node) >+ { >+ return node; >+ } >+ >+ visitStructType(node) >+ { >+ return node; >+ } >+ >+ visitTypeDef(node) >+ { >+ return node; >+ } >+ >+ visitTypeRef(node) >+ { >+ return node; >+ } >+ >+ visitTypeVariable(node) >+ { >+ return node; >+ } >+ >+ visitVariableDecl(node) >+ { >+ return node.type; >+ } >+ >+ visitVariableRef(node) >+ { >+ return node.variable.type; >+ } >+ >+ visitBlock(node) >+ { >+ throw new Error("Block has no type"); >+ } >+ >+ visitBoolLiteral(node) >+ { >+ throw new Error("BoolLiteral has no type"); >+ } >+ >+ visitBreak(node) >+ { >+ throw new Error("Break has no type"); >+ } >+ >+ visitConstexprTypeParameter(node) >+ { >+ throw new Error("ConstexprTypeParameter has no type"); >+ } >+ >+ visitContinue(node) >+ { >+ throw new Error("Continue has no type"); >+ } >+ >+ visitConvertPtrToArrayRefExpression(node) >+ { >+ throw new Error("ConvertPtrToArrayRefExpression has no type"); >+ } >+ >+ visitDereferenceExpression(node) >+ { >+ throw new Error("DereferenceExpression has no type"); >+ } >+ >+ visitDoWhileLoop(node) >+ { >+ throw new Error("DoWhileLoop has no type"); >+ } >+ >+ visitEnumLiteral(node) >+ { >+ throw new Error("EnumLiteral has no type"); >+ } >+ >+ visitEnumMember(node) >+ { >+ throw new Error("EnumMember has no type"); >+ } >+ >+ visitForLoop(node) >+ { >+ throw new Error("ForLoop has no type"); >+ } >+ visitGenericLiteral(node) >+ { >+ throw new Error("GenericLiteral has no type"); >+ } >+ visitIfStatement(node) >+ { >+ throw new Error("IfStatement has no type"); >+ } >+ >+ visitProgram(node) >+ { >+ throw new Error("Program has no type"); >+ } >+ >+ visitProtocolDecl(node) >+ { >+ throw new Error("ProtocolDecl has no type"); >+ } >+ >+ visitProtocolFuncDecl(node) >+ { >+ throw new Error("ProtocolFuncDecl has no type"); >+ } >+ >+ visitProtocolRef(node) >+ { >+ throw new Error("ProtocolRef has no type"); >+ } >+ >+ visitReturn(node) >+ { >+ throw new Error("Return has no type"); >+ } >+ >+ visitSwitchCase(node) >+ { >+ throw new Error("SwitchCase has no type"); >+ } >+ >+ visitSwitchStatement(node) >+ { >+ throw new Error("SwitchStatement has no type"); >+ } >+ >+ visitTrapStatement(node) >+ { >+ throw new Error("TrapStatement has no type"); >+ } >+ >+ visitWhileLoop(node) >+ { >+ throw new Error("WhileLoop has no type"); >+ } >+ } >+ return Node.visit(node, new TypeVisitor()); >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/TypeSorter.ts b/Tools/WebGPUShadingLanguageRI/Metal/TypeSorter.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..a57ed8f08814e6314d00c9b3d53eb3fd37e27671 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/TypeSorter.ts >@@ -0,0 +1,70 @@ >+/* >+ * 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. >+ */ >+ >+// This class finds the topological order for type declarations. >+class TypeSorter extends Visitor { >+ private _typeUnifier: TypeUnifier; >+ private _visitedSet: Set<string>; >+ private _visitedOrder: Type[]; >+ >+ constructor(typeUnifier, types) >+ { >+ super(); >+ this._typeUnifier = typeUnifier; >+ this._visitedSet = new Set(); >+ this._visitedOrder = []; >+ >+ for (let type of types) >+ type.visit(this); >+ } >+ >+ get topologicalOrder() >+ { >+ return this._visitedOrder.slice().reverse(); >+ } >+ >+ visitEnumType(node) >+ { >+ const id = this._typeUnifier.uniqueTypeId(node); >+ if (!this._visitedSet.has(id)) >+ this._visitedOrder.push(node); >+ this._visitedSet.add(id); >+ } >+ >+ visitStructType(node) >+ { >+ const id = this._typeUnifier.uniqueTypeId(node); >+ if (!this._visitedSet.has(id)) { >+ this._visitedOrder.push(node); >+ super.visitStructType(node); >+ } >+ this._visitedSet.add(id); >+ } >+ >+ visitReferenceType(node) >+ { >+ // An empty implementation ensures that we don't recurse into the element type and needlessly create dependencies. >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/TypeUnifier.ts b/Tools/WebGPUShadingLanguageRI/Metal/TypeUnifier.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..ca8f1632bd032badd33b58c2fb044bcf0bc5ee71 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/TypeUnifier.ts >@@ -0,0 +1,293 @@ >+/* >+ * 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. >+ */ >+ >+// Replaces equivalent (but not identical) type instances with identical >+// instances. The SPIR-V compiler depended on toString and allowed for >+// TypeRef instances in the the Type tree. This class replaces each type >+// that it discovers with a unique equivalent instance and collapses >+// TypeRef instances by instantiating them where necessary. In order to >+// determine equivalence it uses a separate stringification algorithm (so >+// that we don't depend on the implementation of toString). >+class TypeUnifier extends Rewriter { >+ >+ private _nativeTypes: Map<any, any>; >+ private _enumTypes: Map<any, any>; >+ private _typeRefs: Map<any, any>; >+ private _structTypes: Map<any, any>; >+ private _arrayTypes: Map<any, any>; >+ private _arrayRefTypes: Map<any, any>; >+ private _pointerTypes: Map<any, any>; >+ private _allTypes: Set<any>; >+ private _typeUniqueID: Map<any, any>; >+ >+ constructor() >+ { >+ super(); >+ this._nativeTypes = new Map(); >+ this._enumTypes = new Map(); >+ this._typeRefs = new Map(); >+ this._structTypes = new Map(); >+ this._arrayTypes = new Map(); >+ this._arrayRefTypes = new Map(); >+ this._pointerTypes = new Map(); >+ this._allTypes = new Set(); >+ this._typeUniqueID = new Map(); >+ } >+ >+ get allTypes() >+ { >+ return this._allTypes; >+ } >+ >+ unifyTypes(node) >+ { >+ return node.visit(this); >+ } >+ >+ uniqueTypeId(type) >+ { >+ return this._typeUniqueID.get(this.uniqueName(this.unifyTypes(type))); >+ } >+ >+ // The Rewriter class doesn't recurse in the desired way, hence the overload. >+ visitFuncDef(node) >+ { >+ if (node.typeParameters.length) >+ throw new Error(`Cannot unify types of polymorphic function ${node}`); >+ node._returnType = node.returnType.visit(this); >+ node._parameters = node.parameters.map(param => param.visit(this)); >+ node._body = node.body.visit(this); >+ return node; >+ } >+ >+ // The Rewriter class doesn't recurse in the desired way, hence the overload. >+ visitFunc(node) >+ { >+ if (node.typeParameters.length) >+ throw new Error(`Cannot unify types of polymorphic function ${node}`); >+ node._returnType = node.returnType.visit(this); >+ node._parameters = node.parameters.map(param => param.visit(this)); >+ return node; >+ } >+ >+ visitNativeFuncInstance(node) >+ { >+ if (node.typeParameters.length) >+ throw new Error(`Cannot unify types of polymorphic function ${node}`); >+ let returnType = node.returnType.visit(this); >+ let parameters = node.parameters.map(param => param.visit(this)); >+ >+ let implementationData = null; >+ >+ if (node.implementationData) { >+ implementationData = Object.assign({}, node.implementationData); >+ implementationData.type = node.implementationData.type.visit(this); >+ } >+ >+ let func = node.func.visit(this); >+ return new NativeFuncInstance(func, returnType, parameters, func.isCast, func.shaderType, implementationData); >+ } >+ >+ visitCallExpression(node) >+ { >+ let result = new CallExpression( >+ node.origin, node.name, >+ node.typeArguments.map(typeArgument => typeArgument.visit(this)), >+ node.argumentList.map(argument => Node.visit(argument, this))); >+ >+ let handleTypeArguments = actualTypeArguments => { >+ if (actualTypeArguments) >+ return actualTypeArguments.map(actualTypeArgument => actualTypeArgument.visit(this)); >+ else >+ return null; >+ } >+ >+ result.actualTypeArguments = handleTypeArguments(node.actualTypeArguments); >+ result.instantiatedActualTypeArguments = handleTypeArguments(node.instantiatedActualTypeArguments); >+ >+ let argumentTypes = node.argumentTypes; >+ if (argumentTypes) >+ result.argumentTypes = argumentTypes.map(argumentType => argumentType.visit(this)); >+ >+ result.func = node.func.visit(this); >+ result.nativeFuncInstance = Node.visit(node.nativeFuncInstance, this); >+ >+ // The possible overloads can contain type variables; this is OK because we never visit them. >+ result.possibleOverloads = node.possibleOverloads; >+ >+ if (node.isCast) >+ result.setCastData(node.returnType.visit(this)); >+ >+ result.resultType = Node.visit(node.resultType, this); >+ result.resultEPtr = node.resultEPtr; >+ >+ return result; >+ } >+ >+ visitTypeRef(node) >+ { >+ if (node.typeArguments.length) { >+ if (node.type.instantiate) >+ return node.type.instantiate(node.typeArguments).visit(this); >+ else >+ throw new Error(`Could not instantiate type ${node}`); >+ } else >+ return node.type.visit(this); >+ } >+ >+ _createTypeIfNotExists(map, value) >+ { >+ const key = this.uniqueName(value); >+ if (map.has(key)) >+ return map.get(key); >+ else { >+ this._allTypes.add(value); >+ map.set(key, value); >+ this._typeUniqueID.set(key, `T${this._typeUniqueID.size}`); >+ return value; >+ } >+ } >+ >+ // Used for determing equivalence of type instances that do not include TypeRef, i.e. fully concrete types. >+ uniqueName(type) >+ { >+ class TypeUniqueNamer extends Visitor { >+ >+ visitNativeType(node) >+ { >+ return node.name; >+ } >+ >+ visitPtrType(node) >+ { >+ return `${node.elementType.visit(this)}* ${node.addressSpace}`; >+ } >+ >+ visitArrayType(node) >+ { >+ return `${node.elementType.visit(this)}[${node.numElements}]`; >+ } >+ >+ visitArrayRefType(node) >+ { >+ return `${node.elementType.visit(this)}[] ${node.addressSpace}`; >+ } >+ >+ visitEnumType(node) >+ { >+ return `enum ${node.name} : ${node.baseType.visit(this)}`; >+ } >+ >+ visitStructType(node) >+ { >+ let fields = []; >+ for (let field of node.fields) >+ fields.push(`${field.type.visit(this)} ${field.name}`); >+ >+ return `struct ${node.name} { ${fields.join("; ")} }`; >+ } >+ } >+ >+ return type.visit(new TypeUniqueNamer()); >+ } >+ >+ visitStructType(node) >+ { >+ const value = new StructType(node.origin, node.name, []); >+ for (let field of node.fields) >+ value.add(new Field(field.origin, field.name, field.type.visit(this))); >+ >+ return this._createTypeIfNotExists(this._structTypes, value); >+ } >+ >+ visitEnumType(node) >+ { >+ const baseType = node.baseType.visit(this); >+ const value = new EnumType(node.origin, node.name, baseType); >+ return this._createTypeIfNotExists(this._enumTypes, value); >+ } >+ >+ visitNativeType(node) >+ { >+ return this._createTypeIfNotExists(this._nativeTypes, node); >+ } >+ >+ visitArrayType(node) >+ { >+ const elementType = node.elementType.visit(this); >+ const value = new ArrayType(node.origin, elementType, node.numElements); >+ return this._createTypeIfNotExists(this._arrayTypes, value); >+ } >+ >+ visitArrayRefType(node) >+ { >+ const elementType = node.elementType.visit(this); >+ const value = new ArrayRefType(node.origin, node.addressSpace, elementType); >+ return this._createTypeIfNotExists(this._arrayRefTypes, value); >+ } >+ >+ visitPtrType(node) >+ { >+ const elementType = node.elementType.visit(this); >+ const value = new PtrType(node.origin, node.addressSpace, elementType); >+ return this._createTypeIfNotExists(this._pointerTypes, value); >+ } >+ >+ typesThatNeedDeclaration() >+ { >+ const declSet = new Set(); >+ for (let type of this._allTypes) { >+ let needsDecl = false; >+ const typeUnifier = this; >+ class NeedsDeclaration extends Visitor >+ { >+ visitElementalType(node) {} >+ visitStructType(node) >+ { >+ needsDecl = !typeUnifier._structIsNative(node); >+ } >+ >+ visitArrayRefType(node) >+ { >+ needsDecl = true; >+ } >+ } >+ type.visit(new NeedsDeclaration()); >+ if (needsDecl) >+ declSet.add(type); >+ } >+ return declSet; >+ } >+ >+ _structIsNative(node) >+ { >+ // TODO: Avoid all this specification and actually tag these types in some reasonable way. >+ if (node.name == "vec2" || node.name == "vec3" || node.name == "vec4") { >+ const elementType = node.fields.next().value.type; >+ return elementType.isNative && (elementType.name == "uint8" || elementType.name == "int32" || elementType.name == "uint32" || elementType.name == "bool" || elementType.name == "float32"); >+ } >+ return false; >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/VarOrFieldDeclaration.ts b/Tools/WebGPUShadingLanguageRI/Metal/VarOrFieldDeclaration.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..27a2c1e85e3a7ac78594e856fec8ab90478d2815 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/VarOrFieldDeclaration.ts >@@ -0,0 +1,68 @@ >+/* >+ * 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. >+ */ >+ >+// The type namer doesn't handle arrays in the style needed for declarations >+// because in MSL array declarations are of the form T x[n] --- I don't believe >+// that there is a way of keeping the whole of the type on the left. >+class VarOrFieldDeclaration { >+ private _typeNamer: MSLTypeNamer; >+ private _type: Type; >+ private _name: string; >+ >+ constructor(typeNamer, type, name) >+ { >+ this._typeNamer = typeNamer; >+ this._type = type; >+ this._name = name; >+ } >+ >+ get typeNamer() >+ { >+ return this._typeNamer; >+ } >+ >+ get type() >+ { >+ return this._type; >+ } >+ >+ get name() >+ { >+ return this._name; >+ } >+ >+ toString() >+ { >+ if (this.type.isArray) { >+ const arrayType = <ArrayType>this.type; >+ const typeName = this.typeNamer.mslTypeName(arrayType.elementType); >+ const numElements = arrayType.numElements.value; >+ return `${typeName} ${this.name}[${numElements}]`; >+ } else { >+ const typeName = this.typeNamer.mslTypeName(this.type); >+ return `${typeName} ${this.name}`; >+ } >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/.gitignore b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/.gitignore >new file mode 100644 >index 0000000000000000000000000000000000000000..c3b9a22cb1aceb00014bf5682b83c33126c9632b >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/.gitignore >@@ -0,0 +1,3 @@ >+WHLSL Tests.xcodeproj/xcuserdata >+WHLSL Tests.xcodeproj/project.xcworkspace/xcshareddata >+WHLSL Tests.xcodeproj/project.xcworkspace/xcuserdata >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.h >new file mode 100644 >index 0000000000000000000000000000000000000000..8529948d2a69df8fc1c861d7850bc503e9f5e9e6 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.h >@@ -0,0 +1,15 @@ >+// >+// AppDelegate.h >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Cocoa/Cocoa.h> >+ >+@interface AppDelegate : NSObject <NSApplicationDelegate> >+ >+ >+@end >+ >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.m >new file mode 100644 >index 0000000000000000000000000000000000000000..368a84a73fdb85b52447560386af20ce25e86cbc >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/AppDelegate.m >@@ -0,0 +1,27 @@ >+// >+// AppDelegate.m >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "AppDelegate.h" >+ >+@interface AppDelegate () >+ >+@end >+ >+@implementation AppDelegate >+ >+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { >+ // Insert code here to initialize your application >+} >+ >+ >+- (void)applicationWillTerminate:(NSNotification *)aNotification { >+ // Insert code here to tear down your application >+} >+ >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/AppIcon.appiconset/Contents.json b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/AppIcon.appiconset/Contents.json >new file mode 100644 >index 0000000000000000000000000000000000000000..2db2b1c7c6c316500a7a34807648434289494ba1 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/AppIcon.appiconset/Contents.json >@@ -0,0 +1,58 @@ >+{ >+ "images" : [ >+ { >+ "idiom" : "mac", >+ "size" : "16x16", >+ "scale" : "1x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "16x16", >+ "scale" : "2x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "32x32", >+ "scale" : "1x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "32x32", >+ "scale" : "2x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "128x128", >+ "scale" : "1x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "128x128", >+ "scale" : "2x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "256x256", >+ "scale" : "1x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "256x256", >+ "scale" : "2x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "512x512", >+ "scale" : "1x" >+ }, >+ { >+ "idiom" : "mac", >+ "size" : "512x512", >+ "scale" : "2x" >+ } >+ ], >+ "info" : { >+ "version" : 1, >+ "author" : "xcode" >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/Contents.json b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/Contents.json >new file mode 100644 >index 0000000000000000000000000000000000000000..da4a164c918651cdd1e11dca5cc62c333f097601 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Assets.xcassets/Contents.json >@@ -0,0 +1,6 @@ >+{ >+ "info" : { >+ "version" : 1, >+ "author" : "xcode" >+ } >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Base.lproj/Main.storyboard b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Base.lproj/Main.storyboard >new file mode 100644 >index 0000000000000000000000000000000000000000..c676d9f74cc567bff56bed1dd565dcdd70beb3df >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Base.lproj/Main.storyboard >@@ -0,0 +1,847 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14269.14" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS"> >+ <dependencies> >+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14269.14"/> >+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> >+ </dependencies> >+ <scenes> >+ <!--Application--> >+ <scene sceneID="JPo-4y-FX3"> >+ <objects> >+ <application id="hnw-xV-0zn" sceneMemberID="viewController"> >+ <menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6"> >+ <items> >+ <menuItem title="WHLSL Tests" id="1Xt-HY-uBw"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="WHLSL Tests" systemMenu="apple" id="uQy-DD-JDr"> >+ <items> >+ <menuItem title="About WHLSL Tests" id="5kV-Vb-QxS"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/> >+ <menuItem title="Preferencesâ¦" keyEquivalent="," id="BOF-NM-1cW"/> >+ <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/> >+ <menuItem title="Services" id="NMo-om-nkz"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/> >+ <menuItem title="Hide WHLSL Tests" keyEquivalent="h" id="Olw-nP-bQN"> >+ <connections> >+ <action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Show All" id="Kd2-mp-pUS"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/> >+ <menuItem title="Quit WHLSL Tests" keyEquivalent="q" id="4sb-4s-VLi"> >+ <connections> >+ <action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="File" id="dMs-cI-mzQ"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="File" id="bib-Uj-vzu"> >+ <items> >+ <menuItem title="New" keyEquivalent="n" id="Was-JA-tGl"> >+ <connections> >+ <action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Openâ¦" keyEquivalent="o" id="IAo-SY-fd9"> >+ <connections> >+ <action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Default" keyEquivalent="D" id="aei-2z-FdS"> >+ <connections> >+ <action selector="loadDefault:" target="Ady-hI-5gd" id="Qkc-mo-M8q"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Mandelbrot" keyEquivalent="d" id="Oo7-Lv-ixZ"> >+ <connections> >+ <action selector="loadMandelbrot:" target="Ady-hI-5gd" id="rBu-TY-q9u"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Julia" keyEquivalent="j" id="ghn-TO-Pf8"> >+ <connections> >+ <action selector="loadJulia:" target="Ady-hI-5gd" id="Ld3-NY-hjZ"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Recent" id="tXI-mr-wws"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ"> >+ <items> >+ <menuItem title="Clear Menu" id="vNY-rz-j42"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Open Native Flat Color" id="4fF-le-bz2"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="loadNativeFlatColor:" target="Ady-hI-5gd" id="D8V-tT-Uue"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Native Mandelbrot" id="vkA-g5-K5f"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="loadNativeMandelbrot:" target="Ady-hI-5gd" id="f0f-zP-EXZ"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Open Native Julia" id="rag-hI-17H"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="loadNativeJulia:" target="Ady-hI-5gd" id="lVh-ll-sg8"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="m54-Is-iLE"/> >+ <menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG"> >+ <connections> >+ <action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Saveâ¦" keyEquivalent="s" id="pxx-59-PXV"> >+ <connections> >+ <action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Save Asâ¦" keyEquivalent="S" id="Bw7-FT-i3A"> >+ <connections> >+ <action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H"> >+ <connections> >+ <action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="aJh-i4-bef"/> >+ <menuItem title="Page Setupâ¦" keyEquivalent="P" id="qIS-W8-SiK"> >+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/> >+ <connections> >+ <action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Printâ¦" keyEquivalent="p" id="aTl-1u-JFS"> >+ <connections> >+ <action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Edit" id="5QF-Oa-p0T"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Edit" id="W48-6f-4Dl"> >+ <items> >+ <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg"> >+ <connections> >+ <action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam"> >+ <connections> >+ <action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/> >+ <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG"> >+ <connections> >+ <action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU"> >+ <connections> >+ <action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL"> >+ <connections> >+ <action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Delete" id="pa3-QI-u2k"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m"> >+ <connections> >+ <action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/> >+ <menuItem title="Find" id="4EN-yA-p0u"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Find" id="1b7-l0-nxx"> >+ <items> >+ <menuItem title="Findâ¦" tag="1" keyEquivalent="f" id="Xz5-n4-O0W"> >+ <connections> >+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Find and Replaceâ¦" tag="12" keyEquivalent="f" id="YEy-JH-Tfz"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye"> >+ <connections> >+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV"> >+ <connections> >+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt"> >+ <connections> >+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd"> >+ <connections> >+ <action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Spelling" id="3IN-sU-3Bg"> >+ <items> >+ <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI"> >+ <connections> >+ <action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7"> >+ <connections> >+ <action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/> >+ <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Substitutions" id="9ic-FL-obx"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Substitutions" id="FeM-D8-WVr"> >+ <items> >+ <menuItem title="Show Substitutions" id="z6F-FW-3nz"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/> >+ <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Smart Quotes" id="hQb-2v-fYv"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Smart Dashes" id="rgM-f4-ycn"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Smart Links" id="cwL-P1-jid"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Data Detectors" id="tRr-pd-1PS"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Text Replacement" id="HFQ-gK-NFA"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Transformations" id="2oI-Rn-ZJC"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Transformations" id="c8a-y6-VQd"> >+ <items> >+ <menuItem title="Make Upper Case" id="vmV-6d-7jI"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Make Lower Case" id="d9M-CD-aMd"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Capitalize" id="UEZ-Bs-lqG"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Speech" id="xrE-MZ-jX0"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Speech" id="3rS-ZA-NoH"> >+ <items> >+ <menuItem title="Start Speaking" id="Ynk-f8-cLZ"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Stop Speaking" id="Oyz-dy-DGm"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Format" id="jxT-CU-nIS"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Format" id="GEO-Iw-cKr"> >+ <items> >+ <menuItem title="Font" id="Gi5-1S-RQB"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq"> >+ <items> >+ <menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq"> >+ <connections> >+ <action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27"> >+ <connections> >+ <action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq"> >+ <connections> >+ <action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S"> >+ <connections> >+ <action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/> >+ <menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL"> >+ <connections> >+ <action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST"> >+ <connections> >+ <action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/> >+ <menuItem title="Kern" id="jBQ-r6-VK2"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Kern" id="tlD-Oa-oAM"> >+ <items> >+ <menuItem title="Use Default" id="GUa-eO-cwY"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Use None" id="cDB-IK-hbR"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Tighten" id="46P-cB-AYj"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Loosen" id="ogc-rX-tC1"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Ligatures" id="o6e-r0-MWq"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Ligatures" id="w0m-vy-SC9"> >+ <items> >+ <menuItem title="Use Default" id="agt-UL-0e3"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Use None" id="J7y-lM-qPV"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Use All" id="xQD-1f-W4t"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Baseline" id="OaQ-X3-Vso"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Baseline" id="ijk-EB-dga"> >+ <items> >+ <menuItem title="Use Default" id="3Om-Ey-2VK"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Superscript" id="Rqc-34-cIF"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Subscript" id="I0S-gh-46l"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Raise" id="2h7-ER-AoG"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Lower" id="1tx-W0-xDw"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/> >+ <menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk"> >+ <connections> >+ <action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/> >+ <menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Text" id="Fal-I4-PZk"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Text" id="d9c-me-L2H"> >+ <items> >+ <menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1"> >+ <connections> >+ <action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb"> >+ <connections> >+ <action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Justify" id="J5U-5w-g23"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4"> >+ <connections> >+ <action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/> >+ <menuItem title="Writing Direction" id="H1b-Si-o9J"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd"> >+ <items> >+ <menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ </menuItem> >+ <menuItem id="YGs-j5-SAR"> >+ <string key="title"> Default</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/> >+ </connections> >+ </menuItem> >+ <menuItem id="Lbh-J2-qVU"> >+ <string key="title"> Left to Right</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/> >+ </connections> >+ </menuItem> >+ <menuItem id="jFq-tB-4Kx"> >+ <string key="title"> Right to Left</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="swp-gr-a21"/> >+ <menuItem title="Selection" enabled="NO" id="cqv-fj-IhA"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ </menuItem> >+ <menuItem id="Nop-cj-93Q"> >+ <string key="title"> Default</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/> >+ </connections> >+ </menuItem> >+ <menuItem id="BgM-ve-c93"> >+ <string key="title"> Left to Right</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/> >+ </connections> >+ </menuItem> >+ <menuItem id="RB4-Sm-HuC"> >+ <string key="title"> Right to Left</string> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/> >+ <menuItem title="Show Ruler" id="vLm-3I-IUL"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5"> >+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> >+ <connections> >+ <action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI"> >+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> >+ <connections> >+ <action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="View" id="H8h-7b-M4v"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="View" id="HyV-fh-RgO"> >+ <items> >+ <menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5"> >+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> >+ <connections> >+ <action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Customize Toolbarâ¦" id="1UK-8n-QPP"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/> >+ <menuItem title="Reset viewport" keyEquivalent="R" id="0RE-Am-xSc"> >+ <connections> >+ <action selector="resetViewport:" target="Ady-hI-5gd" id="PdF-ub-35F"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE"> >+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> >+ <connections> >+ <action selector="toggleSourceList:" target="Ady-hI-5gd" id="iwa-gc-5KM"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa"> >+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> >+ <connections> >+ <action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Window" id="aUF-d1-5bR"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo"> >+ <items> >+ <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV"> >+ <connections> >+ <action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/> >+ </connections> >+ </menuItem> >+ <menuItem title="Zoom" id="R4o-n2-Eq4"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/> >+ </connections> >+ </menuItem> >+ <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/> >+ <menuItem title="Bring All to Front" id="LE2-aR-0XJ"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <connections> >+ <action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ <menuItem title="Help" id="wpr-3q-Mcd"> >+ <modifierMask key="keyEquivalentModifierMask"/> >+ <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ"> >+ <items> >+ <menuItem title="WHLSL Tests Help" keyEquivalent="?" id="FKE-Sm-Kum"> >+ <connections> >+ <action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/> >+ </connections> >+ </menuItem> >+ </items> >+ </menu> >+ </menuItem> >+ </items> >+ </menu> >+ <connections> >+ <outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/> >+ </connections> >+ </application> >+ <customObject id="Voe-Tx-rLC" customClass="AppDelegate"/> >+ <customObject id="YLy-65-1bz" customClass="NSFontManager"/> >+ <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> >+ </objects> >+ <point key="canvasLocation" x="75" y="0.0"/> >+ </scene> >+ <!--Window Controller--> >+ <scene sceneID="R2V-B0-nI4"> >+ <objects> >+ <windowController id="B8D-0N-5wS" sceneMemberID="viewController"> >+ <window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA"> >+ <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> >+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> >+ <rect key="contentRect" x="196" y="240" width="480" height="270"/> >+ <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/> >+ <connections> >+ <outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/> >+ </connections> >+ </window> >+ <connections> >+ <segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/> >+ </connections> >+ </windowController> >+ <customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> >+ </objects> >+ <point key="canvasLocation" x="75" y="250"/> >+ </scene> >+ <!--View Controller--> >+ <scene sceneID="hIz-AP-VOD"> >+ <objects> >+ <viewController id="XfG-lQ-9wD" customClass="ViewController" sceneMemberID="viewController"> >+ <view key="view" wantsLayer="YES" id="m2S-Jp-Qdl"> >+ <rect key="frame" x="0.0" y="0.0" width="1256" height="439"/> >+ <autoresizingMask key="autoresizingMask"/> >+ <subviews> >+ <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zWA-us-Fkf"> >+ <rect key="frame" x="14" y="13" width="90" height="32"/> >+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> >+ <buttonCell key="cell" type="push" title="Compile" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="1K5-PN-nLE"> >+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> >+ <font key="font" metaFont="system"/> >+ <string key="keyEquivalent">r</string> >+ <modifierMask key="keyEquivalentModifierMask" command="YES"/> >+ </buttonCell> >+ <connections> >+ <action selector="compileClicked:" target="XfG-lQ-9wD" id="1FR-KE-nty"/> >+ </connections> >+ </button> >+ <scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="egF-8L-cI6"> >+ <rect key="frame" x="20" y="61" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/> >+ <clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="HW8-L7-3PX"> >+ <rect key="frame" x="0.0" y="0.0" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> >+ <subviews> >+ <textView ambiguous="YES" importsGraphics="NO" richText="NO" verticallyResizable="YES" findStyle="bar" smartInsertDelete="YES" id="pRP-9d-8nB"> >+ <rect key="frame" x="0.0" y="0.0" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> >+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> >+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> >+ <size key="minSize" width="400" height="358"/> >+ <size key="maxSize" width="1317" height="10000000"/> >+ <attributedString key="textStorage"> >+ <fragment content="WHLSLâ¨TextView"> >+ <attributes> >+ <color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/> >+ <font key="NSFont" size="12" name="Menlo-Regular"/> >+ <paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/> >+ </attributes> >+ </fragment> >+ </attributedString> >+ <color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/> >+ </textView> >+ </subviews> >+ </clipView> >+ <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="1T4-PL-dI4"> >+ <rect key="frame" x="384" y="0.0" width="16" height="358"/> >+ <autoresizingMask key="autoresizingMask"/> >+ </scroller> >+ </scrollView> >+ <scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tuu-uc-Dxg"> >+ <rect key="frame" x="428" y="61" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/> >+ <clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="1Us-pH-zAs"> >+ <rect key="frame" x="0.0" y="0.0" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> >+ <subviews> >+ <textView ambiguous="YES" importsGraphics="NO" richText="NO" verticallyResizable="YES" findStyle="bar" smartInsertDelete="YES" id="82n-yv-OVo"> >+ <rect key="frame" x="0.0" y="0.0" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> >+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> >+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> >+ <size key="minSize" width="400" height="358"/> >+ <size key="maxSize" width="1391" height="10000000"/> >+ <color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/> >+ </textView> >+ </subviews> >+ </clipView> >+ <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="ev9-xr-MSP"> >+ <rect key="frame" x="384" y="0.0" width="16" height="358"/> >+ <autoresizingMask key="autoresizingMask"/> >+ </scroller> >+ </scrollView> >+ <customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9FG-iv-6pr" customClass="CustomMetalView"> >+ <rect key="frame" x="836" y="61" width="400" height="358"/> >+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> >+ </customView> >+ <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aSY-2r-vMu"> >+ <rect key="frame" x="106" y="20" width="1132" height="18"/> >+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> >+ <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="JK0-3q-epW"> >+ <font key="font" metaFont="system"/> >+ <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> >+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> >+ </textFieldCell> >+ </textField> >+ </subviews> >+ </view> >+ <connections> >+ <outlet property="debugLabel" destination="aSY-2r-vMu" id="hSC-9N-nj9"/> >+ <outlet property="metalView" destination="9FG-iv-6pr" id="d1K-E7-8zL"/> >+ <outlet property="mslTextView" destination="82n-yv-OVo" id="eoE-3h-vhV"/> >+ <outlet property="mslViewContainer" destination="tuu-uc-Dxg" id="Z3D-cP-qY2"/> >+ <outlet property="whlslTextView" destination="pRP-9d-8nB" id="Muf-bo-NKk"/> >+ <outlet property="whlslViewContainer" destination="egF-8L-cI6" id="DIG-j2-2tb"/> >+ </connections> >+ </viewController> >+ <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> >+ </objects> >+ <point key="canvasLocation" x="-332" y="911.5"/> >+ </scene> >+ </scenes> >+</document> >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.h >new file mode 100644 >index 0000000000000000000000000000000000000000..9f40750336f792b9c71b0bcd302ead62224af753 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.h >@@ -0,0 +1,24 @@ >+// >+// CompileResult.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/12/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface CompileResult : NSObject >+ >+- (instancetype)initWithMetalSource:(NSString*)source functionNameMap:(NSDictionary<NSString*,NSArray<NSString*>*>*)map; >+ >+@property (readonly) NSString *source; >+@property (readonly) NSDictionary<NSString*, NSArray<NSString*>*>* functionNameMap; >+ >+- (NSString*)defaultInstanceMethodForFunctionName:(NSString*)functionName; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.m >new file mode 100644 >index 0000000000000000000000000000000000000000..e7b16964fafb2be8b5573c6a0177873a8aa96198 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CompileResult.m >@@ -0,0 +1,34 @@ >+// >+// CompileResult.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/12/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "CompileResult.h" >+ >+@interface CompileResult () >+ >+@property NSString *source; >+@property NSDictionary<NSString*, NSArray<NSString*>*>* functionNameMap; >+ >+@end >+ >+@implementation CompileResult >+ >+- (instancetype)initWithMetalSource:(NSString *)source functionNameMap:(NSDictionary<NSString *, NSArray<NSString *> *> *)map >+{ >+ if (self = [super init]) { >+ self.source = source; >+ self.functionNameMap = map; >+ } >+ return self; >+} >+ >+- (NSString*)defaultInstanceMethodForFunctionName:(NSString *)functionName >+{ >+ return [self.functionNameMap[functionName] firstObject]; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.h >new file mode 100644 >index 0000000000000000000000000000000000000000..afec3a0a8e4f3289be99ff922a9c89320a0cfb45 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.h >@@ -0,0 +1,25 @@ >+// >+// Compiler.h >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+@import Foundation; >+@import JavaScriptCore; >+ >+#import "CompileResult.h" >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface Compiler : NSObject >+ >+- (CompileResult*)compileWhlslToMetal:(NSString*)whlslSource error:(NSError**)error; >+ >+- (void)lexWhlsl:(NSMutableAttributedString *)msl; >+- (void)lexMsl:(NSMutableAttributedString*)msl; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.m >new file mode 100644 >index 0000000000000000000000000000000000000000..be3d2326bd2f263df9413f9d5badce73970a31a5 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Compiler.m >@@ -0,0 +1,130 @@ >+// >+// Compiler.m >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "Compiler.h" >+ >+@import Cocoa; >+@import JavaScriptCore; >+ >+@interface Compiler () >+ >+@property JSContext* context; >+ >+@end >+ >+@implementation Compiler >+ >+- (instancetype)init >+{ >+ self = [super init]; >+ if (self) { >+ self.context = [[JSContext alloc] init]; >+ [self loadScripts]; >+ } >+ return self; >+} >+ >+- (void)loadScripts >+{ >+ __weak JSContext* weakContext = self.context; >+ __block NSMutableSet<NSString*>* alreadyLoaded = [NSMutableSet new]; >+ void (^loadFunction)(NSString *) = ^void(NSString* name) { >+ if (![alreadyLoaded containsObject:name]) { >+ NSString* path = [[NSBundle mainBundle] pathForResource:[name stringByDeletingPathExtension] ofType:@"js"]; >+ NSError* loadError = nil; >+ NSString* src = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&loadError]; >+ if (loadError) >+ NSLog(@"Loading %@ failed: %@", name, loadError.localizedDescription); >+ else { >+ [weakContext evaluateScript:src]; >+ [alreadyLoaded addObject:name]; >+ } >+ } else >+ NSLog(@"Attempting to load duplicate file %@", name); >+ }; >+ self.context[@"load"] = loadFunction; >+ >+ loadFunction(@"All.js"); >+ loadFunction(@"compiler.js"); >+} >+ >+- (CompileResult*)compileWhlslToMetal:(NSString *)whlslSource error:(NSError * _Nullable __autoreleasing *)error >+{ >+ JSValue *compileFunction = [self.context objectForKeyedSubscript:@"whlslToMsl"]; >+ if (compileFunction) { >+ JSValue * result = [compileFunction callWithArguments:@[whlslSource]]; >+ if (result) { >+ if ([result hasProperty:@"_error"] && [result hasProperty:@"_metalShaderLanguageSource"] && [result hasProperty:@"_originalFunctionNameToMangledNames"]) { >+ if ([[result valueForProperty:@"_error"] isNull]) { >+ NSString *src = [[result valueForProperty:@"_metalShaderLanguageSource"] toString]; >+ NSDictionary *map = [[result valueForProperty:@"_originalFunctionNameToMangledNames"] toDictionary]; >+ return [[CompileResult alloc] initWithMetalSource:src functionNameMap:map]; >+ } >+ >+ *error = [NSError errorWithDomain:@"WhlslCompiler" code:1 userInfo:@{ NSLocalizedDescriptionKey: [[result valueForProperty:@"_error"] toString]}]; >+ return nil; >+ } >+ >+ *error = [NSError errorWithDomain:@"WHLSL Compiler" code:2 userInfo:@{ NSLocalizedDescriptionKey: @"Keys not present in result" }]; >+ return nil; >+ } >+ >+ *error = [NSError errorWithDomain:@"WhlslCompiler" code:3 userInfo:@{ NSLocalizedDescriptionKey: @"Compilation failed" }]; >+ return nil; >+ >+ } >+ >+ *error = [NSError errorWithDomain:@"WhlslCompiler" code:4 userInfo:@{ NSLocalizedDescriptionKey: @"Didn't find compilation function" }]; >+ return nil; >+} >+ >+- (void)lexWhlsl:(NSMutableAttributedString *)whlsl >+{ >+ [self applyStyleInformationWithFunction:@"lexWHLSL" toAttributedString:whlsl]; >+} >+ >+- (void)lexMsl:(NSMutableAttributedString *)msl >+{ >+ [self applyStyleInformationWithFunction:@"lexMsl" toAttributedString:msl]; >+} >+ >+- (void)applyStyleInformationWithFunction:(NSString*)functionName toAttributedString:(NSMutableAttributedString*)attrString >+{ >+ if (!attrString) >+ return; >+ >+ JSValue *lexFunction = [self.context objectForKeyedSubscript:functionName]; >+ if (lexFunction) { >+ JSValue *result = [lexFunction callWithArguments:@[ attrString.string ]]; >+ if (result) { >+ [attrString setAttributes:@{} range:NSMakeRange(0, attrString.length)]; >+ >+ for (NSDictionary* value in result.toArray) { >+ NSUInteger startIndex = [(NSNumber*)[value objectForKeyedSubscript:@"_startIndex"] unsignedIntegerValue]; >+ NSUInteger length = [(NSString*)[value objectForKeyedSubscript:@"_src"] length]; >+ NSRange range = NSMakeRange(startIndex, length); >+ NSString *style = [value objectForKeyedSubscript:@"_type"]; >+ >+ if ([style isEqualToString:@"comment"]) >+ [attrString setAttributes:@{ NSForegroundColorAttributeName: [NSColor colorWithWhite:158.0 / 255 alpha:1], NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:24] } range:range]; >+ else if ([style isEqualToString:@"directive"]) >+ [attrString setAttributes:@{ NSForegroundColorAttributeName: [NSColor colorWithDeviceRed:252.0 / 255 green:143.0 / 255 blue:63.0 / 255 alpha:1], NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:24] } range:range]; >+ else if ([style isEqualToString:@"literal"]) >+ [attrString setAttributes:@{ NSForegroundColorAttributeName: [NSColor colorWithDeviceRed:150.0 / 255 green:134.0 / 255 blue:245.0 / 255 alpha:1], NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:24]} range:range]; >+ else if ([style isEqualToString:@"type"] || [style isEqualToString:@"keyword"]) >+ [attrString setAttributes:@{ NSForegroundColorAttributeName: [NSColor colorWithDeviceRed:253.0 / 255 green:95.0 / 255 blue:162.0 / 255 alpha:1], NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:24]} range:range]; >+ else >+ [attrString setAttributes:@{ NSForegroundColorAttributeName: [NSColor whiteColor], NSFontAttributeName: [NSFont fontWithName:@"Menlo" size:24] } range:range]; >+ } >+ } else >+ NSLog(@"Lexing failed"); >+ } else >+ NSLog(@"No lex function"); >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.h >new file mode 100644 >index 0000000000000000000000000000000000000000..25771b57e3bcc24b3aa6853bab86d1551004c4f5 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.h >@@ -0,0 +1,28 @@ >+// >+// CustomMetalView.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+#import <MetalKit/MetalKit.h> >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@class CustomMetalView; >+ >+@protocol CustomMetalViewDelegate <NSObject> >+ >+- (void)customMetalView:(CustomMetalView*)metalView scrolledDeltaX:(CGFloat)deltaX deltaY:(CGFloat)deltaY; >+ >+@end >+ >+@interface CustomMetalView : MTKView >+ >+@property id<CustomMetalViewDelegate> scrollDelegate; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.m >new file mode 100644 >index 0000000000000000000000000000000000000000..9bf02a5b1514e6e3f3a74f0d1984539b21a04f47 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/CustomMetalView.m >@@ -0,0 +1,18 @@ >+// >+// CustomMetalView.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "CustomMetalView.h" >+ >+@implementation CustomMetalView >+ >+- (void)scrollWheel:(NSEvent *)event >+{ >+ [self.scrollDelegate customMetalView:self scrolledDeltaX:event.deltaX deltaY:event.deltaY]; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Default.whlsl b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Default.whlsl >new file mode 100644 >index 0000000000000000000000000000000000000000..c413c66dcb45e4235aa5b8613390409c62d131ee >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Default.whlsl >@@ -0,0 +1,24 @@ >+struct VertexInput { >+ float2 position; >+ float2 uv; >+} >+ >+struct VertexOutput { >+ float4 wsl_Position; >+} >+ >+struct FragmentOutput { >+ float4 wsl_Color; >+} >+ >+vertex VertexOutput vertexShader(VertexInput vertexInput) { >+ VertexOutput result; >+ result.wsl_Position = float4(vertexInput.position, 0., 1.); >+ return result; >+} >+ >+fragment FragmentOutput fragmentShader(VertexOutput stageIn) { >+ FragmentOutput result; >+ result.wsl_Color = float4(0.0, 1.0, 0.0, 1.0); >+ return result; >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Julia.whlsl b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Julia.whlsl >new file mode 100644 >index 0000000000000000000000000000000000000000..54bee30748181d2db81b52f0c1f2fd72b2925577 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Julia.whlsl >@@ -0,0 +1,103 @@ >+struct VertexInput { >+ float2 position; >+ float2 uv; >+} >+ >+struct VertexOutput { >+ float4 wsl_Position; >+ float2 uv; >+} >+ >+struct FragmentOutput { >+ float4 wsl_Color; >+} >+ >+vertex VertexOutput vertexShader(VertexInput vertexInput) { >+ VertexOutput result; >+ result.wsl_Position = float4(vertexInput.position, 0., 1.); >+ result.uv = vertexInput.uv; >+ return result; >+} >+ >+fragment FragmentOutput fragmentShader(VertexOutput stageIn) { >+ FragmentOutput result; >+ float m = julia(stageIn.uv); >+ float3 hot = float3(1, 1, 1); >+ float3 cold = float3(0, 1, 0.1); >+ float3 res = interpolate(cold, hot, m); >+ res = hslToRgb(res); >+ result.wsl_Color = float4(res, 1); >+ return result; >+} >+ >+float3 interpolate(float3 x, float3 y, float z) >+{ >+ float3 res; >+ res.x = x.x + (y.x - x.x) * z; >+ res.y = x.y + (y.y - x.y) * z; >+ res.z = x.z + (y.z - x.z) * z; >+ return res; >+} >+ >+float hueToRgb(float p, float q, float t) >+{ >+if(t < 0.0) t += 1.0; >+ if(t > 1.0) t -= 1.0; >+ if(t < 1.0/6.0) return p + (q - p) * 6.0 * t; >+ if(t < 1.0/2.0) return q; >+ if(t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0; >+ return p; >+} >+ >+float3 hslToRgb(float3 hsl) >+{ >+ float3 rgb; >+ float h = hsl.x; >+ float s = hsl.y; >+ float l = hsl.z; >+ if(s == 0){ >+ rgb = float3(l, l, l); >+ } else { >+ float q; >+ if (l < 0.5) { q = l * (1.0 + s); } else { q = l + s - l * s; } >+ float p = 2.0 * l - q; >+ rgb.x = hueToRgb(p, q, h + 1.0/3.0); >+ rgb.y = hueToRgb(p, q, h); >+ rgb.z = hueToRgb(p, q, h - 1.0/3.0); >+ } >+ >+ return rgb; >+ >+} >+ >+float julia(float2 uv) >+{ >+ float n = 2.0f; >+ float2 z; >+ float2 c; >+ float2 scale = float2(2, 2.9); >+ float2 center = float2(0.7, 0); >+ int iter = 100; >+ c.x = 1.3333 * (uv.x - 0.5) * scale.x - center.x; >+ c.y = (uv.y - 0.5) * scale.y - center.y; >+ z = c; >+ int i; >+ for (i = 0; i < iter; i++) { >+ float x = pow(z.x * z.x + z.y * z.y, n / 2.0) * cos(n * atan2(z.y, z.x)) + c.x; >+ float y = pow(z.x * z.x + z.y * z.y, n / 2.0) * sin(n * atan2(z.y, z.x)) + c.y; >+ >+ if(pow(x, 2.0f) + pow(y, 2.0f) > 16.0f) break; >+ z.x = x; >+ z.y = y; >+ } >+ float res; >+ if (i < iter) { >+ float log_zn = log( z.x*z.x + z.y*z.y ) / 2.0f; >+ float nu = log( log_zn / log(n) ) / log(2.0f); >+ res = (float(i) + 1 - nu) / float(iter); >+ } else { >+ res = 1; >+ } >+ return res; >+} >+ >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Mandelbrot.whlsl b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Mandelbrot.whlsl >new file mode 100644 >index 0000000000000000000000000000000000000000..521f0ced4060597803d0f867e6cc0d7729b4e91a >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Demo shaders/Mandelbrot.whlsl >@@ -0,0 +1,98 @@ >+struct VertexInput { >+ float2 position; >+ float2 uv; >+} >+ >+struct VertexOutput { >+ float4 wsl_Position; >+ float2 uv; >+} >+ >+struct FragmentOutput { >+ float4 wsl_Color; >+} >+ >+vertex VertexOutput vertexShader(VertexInput vertexInput) { >+ VertexOutput result; >+ result.wsl_Position = float4(vertexInput.position, 0., 1.); >+ result.uv = vertexInput.uv; >+ return result; >+} >+ >+fragment FragmentOutput fragmentShader(VertexOutput stageIn) { >+ FragmentOutput result; >+ float m = mandelbrot(stageIn.uv); >+ float3 hot = float3(1, 1, 1); >+ float3 cold = float3(0, 1, 0.1); >+ float3 res = interpolate(cold, hot, m); >+ res = hslToRgb(res); >+ result.wsl_Color = float4(res, 1); >+ return result; >+} >+ >+float3 interpolate(float3 x, float3 y, float z) >+{ >+ float3 res; >+ res.x = x.x + (y.x - x.x) * z; >+ res.y = x.y + (y.y - x.y) * z; >+ res.z = x.z + (y.z - x.z) * z; >+ return res; >+} >+ >+float hueToRgb(float p, float q, float t) >+{ >+ if(t < 0.0) t += 1.0; >+ if(t > 1.0) t -= 1.0; >+ if(t < 1.0/6.0) return p + (q - p) * 6.0 * t; >+ if(t < 1.0/2.0) return q; >+ if(t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0; >+ return p; >+} >+ >+float3 hslToRgb(float3 hsl) >+{ >+ float3 rgb; >+ float h = hsl.x; >+ float s = hsl.y; >+ float l = hsl.z; >+ if(s == 0){ >+ rgb = float3(l, l, l); >+ } else { >+ float q; >+ if (l < 0.5) { q = l * (1.0 + s); } else { q = l + s - l * s; } >+ float p = 2.0 * l - q; >+ rgb.x = hueToRgb(p, q, h + 1.0/3.0); >+ rgb.y = hueToRgb(p, q, h); >+ rgb.z = hueToRgb(p, q, h - 1.0/3.0); >+ } >+ >+ return rgb; >+} >+ >+float mandelbrot(float2 uv) >+{ >+ float2 z; >+ float2 c = uv; >+ int iter = 100; >+ z = c; >+ int i; >+ for (i = 0; i < iter; i++) { >+ float x = (z.x * z.x - z.y * z.y) + c.x; >+ float y = (z.y * z.x + z.x * z.y) + c.y; >+ >+ if(pow(x, 2.0f) + pow(y, 2.0f) > 256.0) break; >+ z.x = x; >+ z.y = y; >+ } >+ float res; >+ if (i < iter) { >+ float log_zn = log( z.x*z.x + z.y*z.y ) / 2; >+ float nu = log( log_zn / log(2.0f) ) / log(2.0f); >+ res = (float(i) + 1 - nu) / float(iter); >+ } else { >+ res = 1; >+ } >+return res; >+} >+ >+ >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Info.plist b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Info.plist >new file mode 100644 >index 0000000000000000000000000000000000000000..01857f52dab33c6e0e0c3c3f28da60461a07a57e >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Info.plist >@@ -0,0 +1,32 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> >+<plist version="1.0"> >+<dict> >+ <key>CFBundleDevelopmentRegion</key> >+ <string>$(DEVELOPMENT_LANGUAGE)</string> >+ <key>CFBundleExecutable</key> >+ <string>$(EXECUTABLE_NAME)</string> >+ <key>CFBundleIconFile</key> >+ <string></string> >+ <key>CFBundleIdentifier</key> >+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> >+ <key>CFBundleInfoDictionaryVersion</key> >+ <string>6.0</string> >+ <key>CFBundleName</key> >+ <string>$(PRODUCT_NAME)</string> >+ <key>CFBundlePackageType</key> >+ <string>APPL</string> >+ <key>CFBundleShortVersionString</key> >+ <string>1.0</string> >+ <key>CFBundleVersion</key> >+ <string>1</string> >+ <key>LSMinimumSystemVersion</key> >+ <string>$(MACOSX_DEPLOYMENT_TARGET)</string> >+ <key>NSHumanReadableCopyright</key> >+ <string>Copyright © 2018 Apple, Inc. All rights reserved.</string> >+ <key>NSMainStoryboardFile</key> >+ <string>Main</string> >+ <key>NSPrincipalClass</key> >+ <string>NSApplication</string> >+</dict> >+</plist> >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Metal equivalents/Shaders.metal b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Metal equivalents/Shaders.metal >new file mode 100644 >index 0000000000000000000000000000000000000000..111c34b0fce9e72989632bd68f46afbf9fc39da2 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Metal equivalents/Shaders.metal >@@ -0,0 +1,179 @@ >+// >+// FlatColor.metal >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+// This file is a hand-modified version of the WHLSL compiler output >+ >+#include <metal_stdlib> >+using namespace metal; >+ >+struct VertexOutput { >+ float4 position [[position]]; >+ float2 uv; >+}; >+ >+struct VertexInput { >+ float2 position [[attribute(0)]]; >+ float2 uv [[attribute(1)]]; >+}; >+ >+struct FragmentOutput { >+ float4 color [[color(0)]]; >+}; >+ >+vertex VertexOutput flatColorVertexShader(VertexInput in [[stage_in]]) >+{ >+ VertexOutput out; >+ out.position = float4(in.position, 0, 1); >+ return out; >+} >+ >+fragment FragmentOutput flatColorFragmentShader(VertexOutput in [[stage_in]]) >+{ >+ FragmentOutput out; >+ out.color = float4(0, 1, 0, 1); >+ return out; >+} >+ >+float3 interpolate(float3 x, float3 y, float z); >+float hueToRgb(float p, float q, float t); >+float3 hslToRgb(float3 hsl); >+float mandelbrot(float2 uv); >+ >+vertex VertexOutput mandelbrotVertexShader(VertexInput vertexInput [[stage_in]]) { >+ VertexOutput result; >+ result.position = float4(vertexInput.position, 0., 1.); >+ result.uv = vertexInput.uv; >+ return result; >+} >+ >+fragment FragmentOutput mandelbrotFragmentShader(VertexOutput stageIn [[stage_in]]) { >+ FragmentOutput result; >+ const float m = mandelbrot(stageIn.uv); >+ const float3 hot = float3(1, 1, 1); >+ const float3 cold = float3(0, 1, 0.1); >+ const float3 res = hslToRgb(interpolate(cold, hot, m)); >+ result.color = float4(res, 1); >+ return result; >+} >+ >+float3 interpolate(float3 x, float3 y, float z) >+{ >+ float3 res; >+ res.x = x.x + (y.x - x.x) * z; >+ res.y = x.y + (y.y - x.y) * z; >+ res.z = x.z + (y.z - x.z) * z; >+ return res; >+} >+ >+float hueToRgb(float p, float q, float t) >+{ >+ if(t < 0.0) t += 1.0; >+ if(t > 1.0) t -= 1.0; >+ if(t < 1.0/6.0) return p + (q - p) * 6.0 * t; >+ if(t < 1.0/2.0) return q; >+ if(t < 2.0/3.0) return p + (q - p) * (2.0/3.0 - t) * 6.0; >+ return p; >+} >+ >+float3 hslToRgb(float3 hsl) >+{ >+ float3 rgb; >+ float h = hsl.x; >+ float s = hsl.y; >+ float l = hsl.z; >+ if(s == 0){ >+ rgb = float3(l, l, l); >+ } else { >+ float q; >+ if (l < 0.5) { q = l * (1.0 + s); } else { q = l + s - l * s; } >+ float p = 2.0 * l - q; >+ rgb.x = hueToRgb(p, q, h + 1.0/3.0); >+ rgb.y = hueToRgb(p, q, h); >+ rgb.z = hueToRgb(p, q, h - 1.0/3.0); >+ } >+ >+ return rgb; >+} >+ >+float mandelbrot(float2 uv) >+{ >+ float2 z; >+ float2 c = uv; >+ int iter = 100; >+ z = c; >+ int i; >+ for (i = 0; i < iter; i++) { >+ float x = (z.x * z.x - z.y * z.y) + c.x; >+ float y = (z.y * z.x + z.x * z.y) + c.y; >+ >+ if(pow(x, 2.0f) + pow(y, 2.0f) > 256.0) break; >+ z.x = x; >+ z.y = y; >+ } >+ float res; >+ if (i < iter) { >+ float log_zn = log( z.x*z.x + z.y*z.y ) / 2; >+ float nu = log( log_zn / log(2.0f) ) / log(2.0f); >+ res = (float(i) + 1 - nu) / float(iter); >+ } else { >+ res = 1; >+ } >+ return res; >+} >+ >+float julia(float2 uv); >+ >+vertex VertexOutput juliaVertexShader(VertexInput vertexInput [[stage_in]]) { >+ VertexOutput result; >+ result.position = float4(vertexInput.position, 0., 1.); >+ result.uv = vertexInput.uv; >+ return result; >+} >+ >+fragment FragmentOutput juliaFragmentShader(VertexOutput stageIn [[stage_in]]) { >+ FragmentOutput result; >+ float m = julia(stageIn.uv); >+ float3 hot = float3(1, 1, 1); >+ float3 cold = float3(0, 1, 0.1); >+ float3 res = interpolate(cold, hot, m); >+ res = hslToRgb(res); >+ result.color = float4(res, 1); >+ return result; >+} >+ >+float julia(float2 uv) >+{ >+ float n = 2.0f; >+ float2 z; >+ float2 c; >+ float2 scale = float2(2, 2.9); >+ float2 center = float2(0.7, 0); >+ int iter = 100; >+ c.x = 1.3333 * (uv.x - 0.5) * scale.x - center.x; >+ c.y = (uv.y - 0.5) * scale.y - center.y; >+ z = c; >+ int i; >+ for (i = 0; i < iter; i++) { >+ float x = pow(z.x * z.x + z.y * z.y, n / 2.0) * cos(n * atan2(z.y, z.x)) + c.x; >+ float y = pow(z.x * z.x + z.y * z.y, n / 2.0) * sin(n * atan2(z.y, z.x)) + c.y; >+ >+ if(pow(x, 2.0f) + pow(y, 2.0f) > 16.0f) break; >+ z.x = x; >+ z.y = y; >+ } >+ float res; >+ if (i < iter) { >+ float log_zn = log( z.x*z.x + z.y*z.y ) / 2.0f; >+ float nu = log( log_zn / log(n) ) / log(2.0f); >+ res = (float(i) + 1 - nu) / float(iter); >+ } else { >+ res = 1; >+ } >+ return res; >+} >+ >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.h >new file mode 100644 >index 0000000000000000000000000000000000000000..54e4e08d3897fdca7a34ffeecd3f02b8bbd43629 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.h >@@ -0,0 +1,26 @@ >+// >+// OffscreenRenderer.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/11/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "Renderer.h" >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface OffscreenRenderer : Renderer >+ >+@property MTLPixelFormat outputPixelFormat; >+ >+- (void)setLibrary:(id<MTLLibrary>)library vertexShaderName:(NSString*)vertexShader fragmentShaderName:(NSString*)fragmentShaderName; >+- (void)readTextureDataToBuffer:(uint8_t*)buffer bytesPerRow:(NSUInteger)bytesPerRow; >+ >+- (int)intValue; >+- (unsigned int)uintValue; >+- (float)floatValue; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.m >new file mode 100644 >index 0000000000000000000000000000000000000000..9b7aa29e7d53e3c578683b4a0992a30533cfa06c >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OffscreenRenderer.m >@@ -0,0 +1,92 @@ >+// >+// OffscreenRenderer.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/11/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "OffscreenRenderer.h" >+ >+@interface OffscreenRenderer () >+{ >+ id<MTLTexture> _outputTexture; >+} >+ >+@end >+ >+@implementation OffscreenRenderer >+ >+- (void)setLibrary:(id<MTLLibrary>)library vertexShaderName:(NSString*)vertexShader fragmentShaderName:(NSString*)fragmentShaderName >+{ >+ [super setLibrary:library vertexShaderName:vertexShader fragmentShaderName:fragmentShaderName pixelFormat:self.outputPixelFormat]; >+} >+ >+- (void)setTargetWidth:(NSUInteger)width setTargetHeight:(NSUInteger)height >+{ >+ [super setTargetWidth:width setTargetHeight:height]; >+ MTLTextureDescriptor *outputDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:self.outputPixelFormat width:self.targetWidth height:self.targetHeight mipmapped:NO]; >+ outputDescriptor.usage = MTLTextureUsageRenderTarget; >+ outputDescriptor.storageMode = MTLStorageModeManaged; >+ _outputTexture = [self.device newTextureWithDescriptor:outputDescriptor]; >+} >+ >+- (MTLRenderPassDescriptor*)renderPassDescriptor >+{ >+ MTLRenderPassDescriptor *renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; >+ >+ renderPassDescriptor.colorAttachments[0].texture = _outputTexture; >+ renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 0); >+ renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; >+ renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; >+ >+ return renderPassDescriptor; >+} >+ >+- (void)configureCommandBufferBeforeCommit:(id<MTLCommandBuffer>)commandBuffer >+{ >+ id <MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder]; >+ [blitEncoder synchronizeResource:_outputTexture]; >+ [blitEncoder endEncoding]; >+} >+ >+- (void)readTextureDataToBuffer:(uint8_t *)buffer bytesPerRow:(NSUInteger)bytesPerRow >+{ >+ // The texture isn't mipmapped, so we use the default level of 0 >+ [_outputTexture getBytes:buffer bytesPerRow:bytesPerRow fromRegion:MTLRegionMake2D(0, 0, self.targetWidth, self.targetHeight) mipmapLevel:0]; >+} >+ >+- (int)intValue >+{ >+ // We always have 4 bytes per pixel >+ NSUInteger length = self.targetWidth * self.targetHeight * 4; >+ uint8_t *buffer = calloc(length, sizeof(uint8_t)); >+ [self readTextureDataToBuffer:(uint8_t*)buffer bytesPerRow:4 * self.targetWidth]; >+ int intValue = ((int*)buffer)[0]; >+ free(buffer); >+ return intValue; >+} >+ >+- (unsigned int)uintValue >+{ >+ // We always have 4 bytes per pixel >+ NSUInteger length = self.targetWidth * self.targetHeight * 4; >+ uint8_t *buffer = calloc(length, sizeof(uint8_t)); >+ [self readTextureDataToBuffer:(uint8_t*)buffer bytesPerRow:4 * self.targetWidth]; >+ unsigned int uintValue = ((unsigned int*)buffer)[0]; >+ free(buffer); >+ return uintValue; >+} >+ >+- (float)floatValue >+{ >+ // We always have 4 bytes per pixel >+ NSUInteger length = self.targetWidth * self.targetHeight * 4; >+ uint8_t *buffer = calloc(length, sizeof(uint8_t)); >+ [self readTextureDataToBuffer:(uint8_t*)buffer bytesPerRow:4 * self.targetWidth]; >+ float floatValue = ((float*)buffer)[0]; >+ free(buffer); >+ return floatValue; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.h >new file mode 100644 >index 0000000000000000000000000000000000000000..ae6bd5f266823a2abad6b6aff117806f2e6b5ee5 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.h >@@ -0,0 +1,25 @@ >+// >+// Renderer.h >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+ >+#import "Renderer.h" >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface OnscreenRenderer : Renderer<MTKViewDelegate> >+ >+- (instancetype)initWithView:(MTKView*)view; >+ >+@property (readonly) MTKView *view; >+ >+- (void)setShaderSource:(NSString*)source vertexShaderName:(NSString*)vertexShader fragmentShaderName:(NSString*)fragmentShader; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.m >new file mode 100644 >index 0000000000000000000000000000000000000000..963b61658173beb29403d9fe627c4ad1d38e3cb2 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/OnscreenRenderer.m >@@ -0,0 +1,65 @@ >+// >+// Renderer.m >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "OnscreenRenderer.h" >+ >+#import <simd/simd.h> >+ >+@interface OnscreenRenderer () >+ >+@property MTKView *view; >+@property CGSize drawableSize; >+ >+@end >+ >+@implementation OnscreenRenderer >+ >+- (instancetype)initWithView:(MTKView *)view >+{ >+ self = [super init]; >+ if (self) { >+ self.view = view; >+ self.view.delegate = self; >+ } >+ return self; >+} >+ >+- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size >+{ >+ [self setTargetWidth:size.width setTargetHeight:size.height]; >+} >+ >+- (void)drawInMTKView:(MTKView *)view >+{ >+ [self draw]; >+} >+ >+- (MTLRenderPassDescriptor*)renderPassDescriptor >+{ >+ return self.view.currentRenderPassDescriptor; >+} >+ >+- (void)configureCommandBufferBeforeCommit:(id<MTLCommandBuffer>)commandBuffer >+{ >+ [commandBuffer presentDrawable:self.view.currentDrawable]; >+} >+ >+- (void)setShaderSource:(NSString *)source vertexShaderName:(NSString *)vertexShaderName fragmentShaderName:(NSString *)fragmentShaderName >+{ >+ MTLCompileOptions *compileOptions = [[MTLCompileOptions alloc] init]; >+ NSError *error = nil; >+ id<MTLLibrary> library = [self.device newLibraryWithSource:source options:compileOptions error:&error]; >+ if (error) { >+ NSLog(@"Compile error: %@", error.localizedDescription); >+ return; >+ } >+ >+ [self setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName pixelFormat:self.view.colorPixelFormat]; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.h >new file mode 100644 >index 0000000000000000000000000000000000000000..d1d4407729e74e1ea2caa165b13a428624b6dfa3 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.h >@@ -0,0 +1,35 @@ >+// >+// Renderer.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/11/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+#import <MetalKit/MetalKit.h> >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface Renderer : NSObject >+ >+@property (nonatomic) simd_float3x3 transformMatrix; >+ >+@property (readonly) id<MTLDevice> device; >+ >+@property (readonly) NSUInteger targetWidth; >+@property (readonly) NSUInteger targetHeight; >+ >+- (void)setTargetWidth:(NSUInteger)width setTargetHeight:(NSUInteger)height; >+ >+- (void)setLibrary:(id<MTLLibrary>)library vertexShaderName:(NSString*)vertexShader fragmentShaderName:(NSString*)fragmentShaderName pixelFormat:(MTLPixelFormat)pixelFormat; >+ >+- (void)draw; >+ >+// Methods that can be overloaded to configure the render pipeline >+- (MTLRenderPassDescriptor*)renderPassDescriptor; >+- (void)configureCommandBufferBeforeCommit:(id<MTLCommandBuffer>)commandBuffer; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.m >new file mode 100644 >index 0000000000000000000000000000000000000000..9db7d4b990dd7ff0bb0f946a4a0df575f646a134 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/Renderer/Renderer.m >@@ -0,0 +1,155 @@ >+// >+// Renderer.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 7/11/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "Renderer.h" >+ >+// This should mirror the structure that is used for the vertex shaders >+typedef struct { >+ vector_float2 position; >+ vector_float2 uv; >+} VertexStruct; >+ >+// A quad that fills the viewport >+static VertexStruct vertexData[] = >+{ >+ // 2D positions >+ { { -1.0, -1.0 }, { 0, 0 } }, >+ { { 1.0, -1.0 }, { 1, 0 } }, >+ { { -1.0, 1.0 }, { 0, 1 } }, >+ { { 1.0, 1.0 }, { 1, 1 } } >+}; >+ >+@interface Renderer () >+ >+@property id<MTLDevice> device; >+@property NSUInteger targetWidth; >+@property NSUInteger targetHeight; >+ >+@end >+ >+@implementation Renderer { >+ id<MTLCommandQueue> _commandQueue; >+ id<MTLLibrary> _library; >+ >+ MTLRenderPipelineDescriptor *_pipelineStateDescriptor; >+ >+ id<MTLRenderPipelineState> _pipelineState; >+} >+ >+- (instancetype)init >+{ >+ self = [super init]; >+ if (self) { >+ _device = MTLCreateSystemDefaultDevice(); >+ _commandQueue = [_device newCommandQueue]; >+ self.transformMatrix = matrix_identity_float3x3; >+ } >+ return self; >+} >+ >+- (void)setLibrary:(id<MTLLibrary>)library vertexShaderName:(NSString*)vertexShaderName fragmentShaderName:(NSString*)fragmentShaderName pixelFormat:(MTLPixelFormat)pixelFormat >+{ >+ _library = library; >+ id<MTLFunction> vertexFunction = [_library newFunctionWithName:vertexShaderName]; >+ id<MTLFunction> fragmentFunction = [_library newFunctionWithName:fragmentShaderName]; >+ >+ // Configure a pipeline descriptor that is used to create a pipeline state >+ _pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; >+ >+ MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor]; >+ vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; >+ vertexDescriptor.attributes[0].bufferIndex = 0; >+ vertexDescriptor.attributes[0].offset = 0; >+ >+ vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; >+ vertexDescriptor.attributes[1].bufferIndex = 0; >+ vertexDescriptor.attributes[1].offset = offsetof(VertexStruct, uv); >+ >+ vertexDescriptor.layouts[0].stride = sizeof(VertexStruct); >+ vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex; >+ >+ _pipelineStateDescriptor.vertexDescriptor = vertexDescriptor; >+ >+ _pipelineStateDescriptor.label = @"Simple Pipeline"; >+ _pipelineStateDescriptor.vertexFunction = vertexFunction; >+ _pipelineStateDescriptor.fragmentFunction = fragmentFunction; >+ _pipelineStateDescriptor.colorAttachments[0].pixelFormat = pixelFormat; >+ >+ NSError *error = nil; >+ _pipelineState = [_device newRenderPipelineStateWithDescriptor:_pipelineStateDescriptor error:&error]; >+ >+ NSAssert(_pipelineState, @"Failed to created pipeline state: %@", error.localizedDescription); >+} >+ >+- (void)setTargetWidth:(NSUInteger)width setTargetHeight:(NSUInteger)height >+{ >+ _targetWidth = width; >+ _targetHeight = height; >+} >+ >+- (void)draw >+{ >+ if (!_pipelineState) >+ return; >+ >+ // Create a new command buffer for each render pass to the current drawable >+ id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer]; >+ commandBuffer.label = @"MyCommand"; >+ >+ MTLRenderPassDescriptor *renderPassDescriptor = [self renderPassDescriptor]; >+ >+ NSAssert(renderPassDescriptor, @"nil MTLRenderPassDescriptor"); >+ >+ renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1, 1, 1, 1); >+ renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; >+ renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; >+ >+ // Create a render command encoder so we can render into something >+ id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; >+ renderEncoder.label = @"MyRenderEncoder"; >+ >+ [renderEncoder setViewport:(MTLViewport) { 0.0, 0.0, _targetWidth, _targetHeight, -1.0, 1.0 }]; >+ >+ [renderEncoder setRenderPipelineState:_pipelineState]; >+ >+ [renderEncoder setVertexBytes:vertexData length:sizeof(vertexData) atIndex:0]; >+ >+ [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; >+ >+ [renderEncoder endEncoding]; >+ >+ [self configureCommandBufferBeforeCommit:commandBuffer]; >+ >+ [commandBuffer commit]; >+ [commandBuffer waitUntilCompleted]; >+} >+ >+- (void)setTransformMatrix:(simd_float3x3)transformMatrix >+{ >+ _transformMatrix = transformMatrix; >+ simd_float3 v0 = matrix_multiply(_transformMatrix, vector3(0.0f, 0.0f, 1.0f)); >+ simd_float3 v1 = matrix_multiply(_transformMatrix, vector3(1.0f, 0.0f, 1.0f)); >+ simd_float3 v2 = matrix_multiply(_transformMatrix, vector3(0.0f, 1.0f, 1.0f)); >+ simd_float3 v3 = matrix_multiply(_transformMatrix, vector3(1.0f, 1.0f, 1.0f)); >+ >+ vertexData[0].uv = vector2(v0.x, v0.y); >+ vertexData[1].uv = vector2(v1.x, v1.y); >+ vertexData[2].uv = vector2(v2.x, v2.y); >+ vertexData[3].uv = vector2(v3.x, v3.y); >+} >+ >+- (MTLRenderPassDescriptor *)renderPassDescriptor >+{ >+ return nil; >+} >+ >+- (void)configureCommandBufferBeforeCommit:(id<MTLCommandBuffer>)commandBuffer >+{ >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.h >new file mode 100644 >index 0000000000000000000000000000000000000000..ab5b40791454248485561947d649acba4bc5149d >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.h >@@ -0,0 +1,32 @@ >+// >+// TestCallArgument.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+ >+typedef enum : NSUInteger { >+ WHLSLTypeInt32, >+ WHLSLTypeUint32, >+ WHLSLTypeUint8, >+ WHLSLTypeFloat, >+ WHLSLTypeBool >+} WHLSLType; >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface TestCallArgument : NSObject >+ >+- (instancetype)initWithValue:(NSNumber*)value type:(WHLSLType)type; >+ >+@property (readonly) NSNumber* value; >+@property (readonly) WHLSLType type; >+ >+- (NSString*)whlslSource; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.m >new file mode 100644 >index 0000000000000000000000000000000000000000..88ba94d3221b55ffa7eaafb893e98d7c006bd17c >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestCallArgument.m >@@ -0,0 +1,44 @@ >+// >+// TestCallArgument.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "TestCallArgument.h" >+ >+@interface TestCallArgument () >+ >+@property NSNumber* value; >+@property WHLSLType type; >+ >+@end >+ >+@implementation TestCallArgument >+ >+- (instancetype)initWithValue:(NSNumber *)value type:(WHLSLType)type >+{ >+ if (self = [super init]) { >+ self.value = value; >+ self.type = type; >+ } >+ return self; >+} >+ >+- (NSString*)whlslSource >+{ >+ switch (self.type) { >+ case WHLSLTypeUint8: >+ case WHLSLTypeUint32: >+ return [NSString stringWithFormat:@"%uu", self.value.unsignedIntValue]; >+ case WHLSLTypeFloat: >+ return [NSString stringWithFormat:@"%f", self.value.floatValue]; >+ case WHLSLTypeBool: >+ return self.value.boolValue ? @"true" : @"false"; >+ case WHLSLTypeInt32: >+ return [NSString stringWithFormat:@"%d", self.value.intValue]; >+ } >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.h >new file mode 100644 >index 0000000000000000000000000000000000000000..eca11ffba46065c13670d292074dc72e790ccbe0 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.h >@@ -0,0 +1,34 @@ >+// >+// TestDescription.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+@import Foundation; >+#import "TestCallArgument.h" >+ >+@class TestFamily; >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface TestDescription : NSObject >+ >+- (instancetype)initWithFunctionName:(NSString*)functionName arguments:(NSArray<TestCallArgument*>*)arguments; >+ >+@property NSString* functionName; >+@property NSArray<TestCallArgument*>* arguments; >+ >+@property WHLSLType returnType; >+@property NSNumber* expectation; >+ >+@property (weak) TestFamily* testFamily; >+@property NSString* fragmentShaderName; >+ >+- (NSString*)callString; >+- (NSString*)fragmentShaderSource; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.m >new file mode 100644 >index 0000000000000000000000000000000000000000..37ced5e36e27e87400a42a91c2864d2c3907fa34 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestDescription.m >@@ -0,0 +1,98 @@ >+// >+// TestDescription.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "TestDescription.h" >+ >+@implementation TestDescription >+ >+- (instancetype)initWithFunctionName:(NSString *)functionName arguments:(NSArray<TestCallArgument *> *)arguments >+{ >+ if (self = [super init]) { >+ self.functionName = functionName; >+ self.arguments = arguments; >+ } >+ return self; >+} >+ >+- (NSString*)callString >+{ >+ NSMutableString* string = [NSMutableString new]; >+ [string appendFormat:@"%@(", self.functionName]; >+ >+ BOOL first = YES; >+ for (TestCallArgument* argument in self.arguments) { >+ if (!first) >+ [string appendFormat:@", %@", argument.whlslSource]; >+ else >+ [string appendString:argument.whlslSource]; >+ first = NO; >+ } >+ >+ [string appendString:@")"]; >+ return string; >+} >+ >+- (NSString*)fragmentShaderSource >+{ >+ NSMutableString* string = [NSMutableString new]; >+ [string appendString:@"fragment "]; >+ switch (self.returnType) { >+ case WHLSLTypeUint8: >+ case WHLSLTypeUint32: >+ [string appendString:@"FragmentOutputUint"]; >+ break; >+ case WHLSLTypeInt32: >+ case WHLSLTypeBool: >+ [string appendString:@"FragmentOutputInt"]; >+ break; >+ case WHLSLTypeFloat: >+ [string appendString:@"FragmentOutputFloat"]; >+ break; >+ } >+ [string appendFormat:@" %@(VertexOutput stageIn)\n", self.fragmentShaderName]; >+ [string appendString:@"{\n"]; >+ >+ switch (self.returnType) { >+ case WHLSLTypeUint8: >+ case WHLSLTypeUint32: >+ [string appendString:@" FragmentOutputUint fragmentOutput;\n"]; >+ break; >+ case WHLSLTypeInt32: >+ case WHLSLTypeBool: >+ [string appendString:@" FragmentOutputInt fragmentOutput;\n"]; >+ break; >+ case WHLSLTypeFloat: >+ [string appendString:@" FragmentOutputFloat fragmentOutput;\n"]; >+ break; >+ } >+ >+ NSString * call = [self callString]; >+ >+ switch (self.returnType) { >+ case WHLSLTypeBool: >+ [string appendFormat:@" if(%@)\n", call]; >+ [string appendString:@" fragmentOutput.wsl_Color = 1;\n"]; >+ [string appendString:@" else\n"]; >+ [string appendString:@" fragmentOutput.wsl_Color = 0;\n"]; >+ break; >+ case WHLSLTypeUint8: >+ [string appendFormat:@" fragmentOutput.wsl_Color = uint(%@);\n", call]; >+ break; >+ case WHLSLTypeUint32: >+ case WHLSLTypeInt32: >+ case WHLSLTypeFloat: >+ [string appendFormat:@" fragmentOutput.wsl_Color = %@;\n", call]; >+ } >+ >+ [string appendString:@" return fragmentOutput;\n"]; >+ [string appendString:@"}\n"]; >+ >+ return string; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.h >new file mode 100644 >index 0000000000000000000000000000000000000000..aa5a8550a37aaeace13afd18f23494200f3ebd33 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.h >@@ -0,0 +1,31 @@ >+// >+// TestFamily.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+#import "TestCallArgument.h" >+#import "TestDescription.h" >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface TestFamily : NSObject >+ >+- (instancetype)initWithName:(NSString*)name source:(NSString*)source; >+ >+@property (readonly) NSString* name; >+@property (readonly) NSString* source; >+ >+- (void)addTestDescription:(TestDescription*)testDescription; >+- (NSArray<TestDescription*>*)testsForReturnType:(WHLSLType)type; >+ >+- (NSString*)fullTestSource; >+ >++ (NSArray<TestFamily*>*)allTests; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.m >new file mode 100644 >index 0000000000000000000000000000000000000000..d56bb25f1df93703cd7e4466a4fab94d7001ca7f >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamily.m >@@ -0,0 +1,164 @@ >+// >+// TestFamily.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "TestFamily.h" >+ >+@import JavaScriptCore; >+ >+@interface TestFamily () >+ >+@property NSString* name; >+@property NSString* source; >+@property NSUInteger fragmentShaderIndex; >+ >+@property NSMutableDictionary<NSNumber*, NSMutableArray<TestDescription*>*>* tests; >+ >+@end >+ >+@implementation TestFamily >+ >+- (instancetype)initWithName:(NSString *)name source:(NSString *)source >+{ >+ if (self = [super init]) { >+ self.name = name; >+ self.source = source; >+ self.tests = [NSMutableDictionary new]; >+ self.tests[@(WHLSLTypeUint8)] = [NSMutableArray new]; >+ self.tests[@(WHLSLTypeUint32)] = [NSMutableArray new]; >+ self.tests[@(WHLSLTypeInt32)] = [NSMutableArray new]; >+ self.tests[@(WHLSLTypeFloat)] = [NSMutableArray new]; >+ self.tests[@(WHLSLTypeBool)] = [NSMutableArray new]; >+ } >+ return self; >+} >+ >+- (void)addTestDescription:(TestDescription *)testDescription >+{ >+ [self.tests[@(testDescription.returnType)] addObject:testDescription]; >+ testDescription.testFamily = self; >+ testDescription.fragmentShaderName = [NSString stringWithFormat:@"%@%lu", self.name, self.fragmentShaderIndex++]; >+} >+ >+- (NSArray<TestDescription*>*)testsForReturnType:(WHLSLType)type >+{ >+ return self.tests[@(type)]; >+} >+ >+- (NSString*)fullTestSource >+{ >+ NSMutableString* source = [NSMutableString new]; >+ >+ [source appendString:[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"_Shared" ofType:@"whlsl"] encoding:NSUTF8StringEncoding error:nil]]; >+ [source appendString:self.source]; >+ [source appendString:@"\n"]; >+ >+ [self.tests enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull type, NSMutableArray<TestDescription *> * _Nonnull tests, BOOL * _Nonnull stop) { >+ for (TestDescription* testDescription in tests) { >+ [source appendFormat:@"%@\n", [testDescription fragmentShaderSource]]; >+ } >+ }]; >+ >+ return source; >+} >+ >++ (NSArray<TestFamily*>*)allTests >+{ >+ JSContext* compilerContext = [JSContext new]; >+ >+ NSString* testFile = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Test" ofType:@"js"] encoding:NSUTF8StringEncoding error:nil]; >+ [compilerContext evaluateScript:testFile]; >+ >+ __block NSString *currentTestName = nil; >+ __block BOOL includeTest = YES; >+ >+ NSMutableArray<TestFamily*>* testFamilies = [NSMutableArray new]; >+ >+ // See the bottom of Test.js >+ compilerContext[@"runningInCocoaHost"] = [JSValue valueWithBool:YES inContext:compilerContext]; >+ >+ compilerContext[@"doPrep"] = ^TestFamily*(NSString* code) { >+ TestFamily* family = [[TestFamily alloc] initWithName:currentTestName source:code]; >+ [testFamilies addObject:family]; >+ includeTest = YES; >+ return family; >+ }; >+ >+ compilerContext.exceptionHandler = ^(JSContext *context, JSValue *exception) { >+ includeTest = NO; >+ }; >+ >+ compilerContext[@"makeInt"] = ^TestCallArgument*(TestFamily* program, NSNumber* number) { >+ return [[TestCallArgument alloc] initWithValue:number type:WHLSLTypeInt32]; >+ }; >+ >+ compilerContext[@"makeUint"] = ^TestCallArgument*(TestFamily* program, NSNumber* number) { >+ return [[TestCallArgument alloc] initWithValue:number type:WHLSLTypeInt32]; >+ }; >+ >+ compilerContext[@"makeUint8"] = ^TestCallArgument*(TestFamily* program, NSNumber* number) { >+ return [[TestCallArgument alloc] initWithValue:number type:WHLSLTypeUint8]; >+ }; >+ >+ compilerContext[@"makeBool"] = ^TestCallArgument*(TestFamily* program, NSNumber* number) { >+ return [[TestCallArgument alloc] initWithValue:number type:WHLSLTypeBool]; >+ }; >+ >+ compilerContext[@"makeFloat"] = ^TestCallArgument*(TestFamily* program, NSNumber* number) { >+ return [[TestCallArgument alloc] initWithValue:number type:WHLSLTypeFloat]; >+ }; >+ >+ compilerContext[@"callFunction"] = ^TestDescription*(TestFamily* program, NSString* functionName, NSArray* typeArguments, NSArray* args) { >+ return [[TestDescription alloc] initWithFunctionName:functionName arguments:args]; >+ }; >+ >+ void(^addTest)(TestFamily*,TestDescription*,NSNumber*,WHLSLType) = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation, WHLSLType type) { >+ if (includeTest) { >+ testDesc.returnType = type; >+ testDesc.expectation = expectation; >+ [program addTestDescription:testDesc]; >+ } >+ }; >+ >+ compilerContext[@"checkInt"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) { >+ addTest(program, testDesc, expectation, WHLSLTypeInt32); >+ }; >+ >+ compilerContext[@"checkUint"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) { >+ addTest(program, testDesc, expectation, WHLSLTypeUint32); >+ }; >+ >+ compilerContext[@"checkFloat"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) { >+ addTest(program, testDesc, expectation, WHLSLTypeFloat); >+ }; >+ >+ compilerContext[@"checkBool"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) { >+ addTest(program, testDesc, expectation, WHLSLTypeBool); >+ }; >+ >+ compilerContext[@"checkUint8"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) { >+ addTest(program, testDesc, expectation, WHLSLTypeUint8); >+ }; >+ >+ // Deliberately not included >+ compilerContext[@"checkEnum"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) {}; >+ compilerContext[@"checkFail"] = ^void(TestFamily* program, TestDescription* testDesc, NSNumber* expectation) {}; >+ compilerContext[@"checkLexerToken"] = ^void(NSString* token, NSNumber* id, NSString* name, NSString* tokenText) {}; >+ >+ JSValue* tests = [compilerContext evaluateScript:@"tests"]; >+ >+ NSArray<NSString*>* testNames = [tests.toDictionary.allKeys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; >+ >+ for (currentTestName in testNames) { >+ JSValue* func = [tests objectForKeyedSubscript:currentTestName]; >+ [func callWithArguments:@[]]; >+ } >+ >+ return testFamilies; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.h >new file mode 100644 >index 0000000000000000000000000000000000000000..1589e3e8cd081018fa1f7dc3caab67812830f92e >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.h >@@ -0,0 +1,26 @@ >+// >+// TestFamilyRunner.h >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Foundation/Foundation.h> >+#import "TestFamily.h" >+ >+NS_ASSUME_NONNULL_BEGIN >+ >+@interface TestFamilyRunner : NSObject >+ >+- (instancetype)initWithTestFamily:(TestFamily*)testFamily; >+ >+@property (readonly) TestFamily* testFamily; >+ >+- (BOOL)executeAllTests; >+ >++ (NSUInteger)executionCount; >+ >+@end >+ >+NS_ASSUME_NONNULL_END >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.m >new file mode 100644 >index 0000000000000000000000000000000000000000..97b5a7e24d567e7607e9fb81fbd7a4e468165ba0 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/TestFamilyRunner.m >@@ -0,0 +1,186 @@ >+// >+// TestFamilyRunner.m >+// WHLSL Tests >+// >+// Created by Thomas Denney on 8/3/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "TestFamilyRunner.h" >+ >+#import "Compiler.h" >+#import "OffscreenRenderer.h" >+ >+static NSUInteger executionCount = 0; >+ >+@interface TestFamilyRunner () >+ >+@property TestFamily* testFamily; >+ >+@end >+ >+@implementation TestFamilyRunner >+ >+- (instancetype)initWithTestFamily:(TestFamily *)testFamily >+{ >+ if (self = [super init]) { >+ self.testFamily = testFamily; >+ } >+ return self; >+} >+ >++ (OffscreenRenderer*)intOffscreenRenderer >+{ >+ static OffscreenRenderer* offscreenRenderer; >+ static dispatch_once_t onceToken; >+ dispatch_once(&onceToken, ^{ >+ offscreenRenderer = [[OffscreenRenderer alloc] init]; >+ [offscreenRenderer setOutputPixelFormat:MTLPixelFormatR32Sint]; >+ [offscreenRenderer setTargetWidth:1 setTargetHeight:1]; >+ }); >+ return offscreenRenderer; >+} >+ >++ (OffscreenRenderer*)uintOffscreenRenderer >+{ >+ static OffscreenRenderer* offscreenRenderer; >+ static dispatch_once_t onceToken; >+ dispatch_once(&onceToken, ^{ >+ offscreenRenderer = [[OffscreenRenderer alloc] init]; >+ [offscreenRenderer setOutputPixelFormat:MTLPixelFormatR32Uint]; >+ [offscreenRenderer setTargetWidth:1 setTargetHeight:1]; >+ }); >+ return offscreenRenderer; >+} >+ >++ (OffscreenRenderer*)floatOffscreenRenderer >+{ >+ static OffscreenRenderer* offscreenRenderer; >+ static dispatch_once_t onceToken; >+ dispatch_once(&onceToken, ^{ >+ offscreenRenderer = [[OffscreenRenderer alloc] init]; >+ [offscreenRenderer setOutputPixelFormat:MTLPixelFormatR32Float]; >+ [offscreenRenderer setTargetWidth:1 setTargetHeight:1]; >+ }); >+ return offscreenRenderer; >+} >+ >++ (Compiler*)compiler >+{ >+ static Compiler* compiler; >+ static dispatch_once_t onceToken; >+ dispatch_once(&onceToken, ^{ >+ compiler = [Compiler new]; >+ }); >+ return compiler; >+} >+ >+- (BOOL)executeAllTests >+{ >+ NSString* whlslSource = self.testFamily.fullTestSource; >+ NSError* whlslCompileError = nil; >+ CompileResult* result = [[TestFamilyRunner compiler] compileWhlslToMetal:whlslSource error:&whlslCompileError]; >+ if (!result) { >+ NSLog(@"[%@]: WHLSL Compile Error: %@", self.testFamily.name, whlslCompileError.localizedDescription); >+ return NO; >+ } >+ >+ NSLog(@"Compiled WHLSL"); >+ >+ id<MTLDevice> device = MTLCreateSystemDefaultDevice(); >+ MTLCompileOptions *compileOptions = [MTLCompileOptions new]; >+ NSError *error = nil; >+ id<MTLLibrary> library = [device newLibraryWithSource:result.source options:compileOptions error:&error]; >+ if (!library) { >+ NSLog(@"[Library]: %@", error.localizedDescription); >+ return NO; >+ } >+ >+ NSLog(@"Compiled metal"); >+ >+ BOOL status = YES; >+ >+ NSString *vertexShaderName = [result defaultInstanceMethodForFunctionName:@"vertexShader"]; >+ >+ OffscreenRenderer *intRenderer = [TestFamilyRunner intOffscreenRenderer]; >+ for (TestDescription* test in [self.testFamily testsForReturnType:WHLSLTypeInt32]) { >+ NSString* fragmentShaderName = [result defaultInstanceMethodForFunctionName:test.fragmentShaderName]; >+ [intRenderer setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [intRenderer draw]; >+ >+ int result = intRenderer.intValue; >+ if (result != test.expectation.intValue) { >+ NSLog(@"[%@]: (result)) %d != %d (expectation)", test.fragmentShaderName, result, test.expectation.intValue); >+ status = NO; >+ } else >+ NSLog(@"[%@]: â ", test.fragmentShaderName); >+ executionCount++; >+ } >+ >+ OffscreenRenderer *uintRenderer = [TestFamilyRunner uintOffscreenRenderer]; >+ for (TestDescription* test in [self.testFamily testsForReturnType:WHLSLTypeUint32]) { >+ NSString* fragmentShaderName = [result defaultInstanceMethodForFunctionName:test.fragmentShaderName]; >+ [uintRenderer setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [uintRenderer draw]; >+ >+ unsigned int result = uintRenderer.uintValue; >+ if (result != test.expectation.unsignedIntValue) { >+ NSLog(@"[%@]: (result)) %u != %u (expectation)", test.fragmentShaderName, result, test.expectation.unsignedIntValue); >+ status = NO; >+ } else >+ NSLog(@"[%@]: â ", test.fragmentShaderName); >+ executionCount++; >+ } >+ >+ for (TestDescription* test in [self.testFamily testsForReturnType:WHLSLTypeUint8]) { >+ NSString* fragmentShaderName = [result defaultInstanceMethodForFunctionName:test.fragmentShaderName]; >+ [uintRenderer setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [uintRenderer draw]; >+ >+ unsigned int result = uintRenderer.uintValue; >+ if (result != test.expectation.unsignedIntValue) { >+ NSLog(@"[%@]: (result)) %u != %u (expectation)", test.fragmentShaderName, result, test.expectation.unsignedIntValue); >+ status = NO; >+ } else >+ NSLog(@"[%@]: â ", test.fragmentShaderName); >+ executionCount++; >+ } >+ >+ OffscreenRenderer *floatRenderer = [TestFamilyRunner floatOffscreenRenderer]; >+ for (TestDescription* test in [self.testFamily testsForReturnType:WHLSLTypeFloat]) { >+ NSString* fragmentShaderName = [result defaultInstanceMethodForFunctionName:test.fragmentShaderName]; >+ [floatRenderer setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [floatRenderer draw]; >+ >+ float result = floatRenderer.floatValue; >+ if (result != test.expectation.floatValue) { >+ NSLog(@"[%@]: (result)) %f != %f (expectation)", test.fragmentShaderName, result, test.expectation.floatValue); >+ status = NO; >+ } else >+ NSLog(@"[%@]: â ", test.fragmentShaderName); >+ executionCount++; >+ } >+ >+ for (TestDescription* test in [self.testFamily testsForReturnType:WHLSLTypeBool]) { >+ NSString* fragmentShaderName = [result defaultInstanceMethodForFunctionName:test.fragmentShaderName]; >+ [intRenderer setLibrary:library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [intRenderer draw]; >+ >+ int result = intRenderer.intValue; >+ if (result != test.expectation.intValue) { >+ NSLog(@"[%@]: (result)) %d != %d (expectation)", test.fragmentShaderName, result, test.expectation.intValue); >+ status = NO; >+ } else >+ NSLog(@"[%@]: â ", test.fragmentShaderName); >+ executionCount++; >+ } >+ >+ return status; >+} >+ >++ (NSUInteger)executionCount >+{ >+ return executionCount; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.h b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.h >new file mode 100644 >index 0000000000000000000000000000000000000000..9f5fcfb69a1059476fe1660a1558e81cf381da72 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.h >@@ -0,0 +1,24 @@ >+// >+// ViewController.h >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Cocoa/Cocoa.h> >+#import <MetalKit/MetalKit.h> >+#import "CustomMetalView.h" >+ >+#import "Compiler.h" >+ >+@interface ViewController : NSViewController<NSGestureRecognizerDelegate, CustomMetalViewDelegate, NSTextViewDelegate> >+ >+@property (unsafe_unretained) IBOutlet NSTextView *whlslTextView; >+@property (unsafe_unretained) IBOutlet NSTextView *mslTextView; >+@property (weak) IBOutlet CustomMetalView *metalView; >+ >+@property Compiler *compiler; >+ >+@end >+ >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.m >new file mode 100644 >index 0000000000000000000000000000000000000000..5a072a1a04cab3743931c4dd95a445f68dbe4723 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/ViewController.m >@@ -0,0 +1,232 @@ >+// >+// ViewController.m >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import "ViewController.h" >+#import "OnscreenRenderer.h" >+ >+@interface ViewController () >+ >+@property OnscreenRenderer *renderer; >+@property NSMagnificationGestureRecognizer *magnifyGesture; >+@property NSRotationGestureRecognizer *rotationGesture; >+@property (weak) IBOutlet NSTextField *debugLabel; >+@property (weak) IBOutlet NSScrollView *whlslViewContainer; >+@property (weak) IBOutlet NSScrollView *mslViewContainer; >+@property id<MTLLibrary> library; >+ >+@end >+ >+@implementation ViewController >+ >+- (void)viewDidLoad { >+ [super viewDidLoad]; >+ >+ [self loadFile:@"Default"]; >+ >+ self.compiler = [[Compiler alloc] init]; >+ >+ self.metalView.device = MTLCreateSystemDefaultDevice(); >+ self.renderer = [[OnscreenRenderer alloc] initWithView:self.metalView]; >+ >+ self.magnifyGesture = [[NSMagnificationGestureRecognizer alloc] initWithTarget:self action:@selector(zoom:)]; >+ self.magnifyGesture.delegate = self; >+ [self.metalView addGestureRecognizer:self.magnifyGesture]; >+ >+ self.rotationGesture = [[NSRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotate:)]; >+ self.rotationGesture.delegate = self; >+ [self.metalView addGestureRecognizer:self.rotationGesture]; >+ >+ self.metalView.scrollDelegate = self; >+ >+ [self viewDidLayout]; >+ >+ self.whlslTextView.delegate = self; >+ >+ self.library = [self.renderer.device newDefaultLibraryWithBundle:[NSBundle mainBundle] error:nil]; >+} >+ >+- (void)viewDidAppear >+{ >+ [super viewDidAppear]; >+ [self updateHighlighting]; >+} >+ >+- (BOOL)gestureRecognizer:(NSGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(nonnull NSGestureRecognizer *)otherGestureRecognizer >+{ >+ return YES; >+} >+ >+- (void)viewDidLayout >+{ >+ [super viewDidLayout]; >+ >+ CGFloat width = CGRectGetWidth(self.view.frame); >+ CGFloat boxWidth = (width - 20 * 2 - 10 * 2) / 3; >+ CGFloat height = CGRectGetHeight(self.view.frame); >+ CGFloat boxHeight = height - 60 - 20; >+ >+ self.whlslViewContainer.frame = CGRectMake(20, 60, boxWidth, boxHeight); >+ self.mslViewContainer.frame = CGRectMake(20 + boxWidth + 10, 60, boxWidth, boxHeight); >+ self.metalView.frame = CGRectMake(20 + boxWidth + 10 + boxWidth + 10, 60, boxWidth, boxHeight); >+ >+ float ratio = boxHeight / (boxWidth / 3); >+ // NOTE: simd_matrix takes columns, not rows! >+ self.renderer.transformMatrix = simd_matrix(simd_make_float3(3, 0, 0), >+ simd_make_float3(0, ratio, 0), >+ simd_make_float3(-2.2, -ratio / 2, 1)); >+ >+ self.debugLabel.stringValue = [NSString stringWithFormat:@"Width = %f, height = %f", boxWidth, boxHeight]; >+} >+ >+- (IBAction)resetViewport:(id)sender >+{ >+ [self viewDidLayout]; >+ [self.metalView setNeedsDisplay:YES]; >+} >+ >+- (IBAction)loadDefault:(id)sender >+{ >+ [self loadFile:@"Default"]; >+} >+ >+- (IBAction)loadMandelbrot:(id)sender >+{ >+ [self loadFile:@"Mandelbrot"]; >+} >+ >+- (IBAction)loadJulia:(id)sender >+{ >+ [self loadFile:@"Julia"]; >+} >+ >+- (void)loadFile:(NSString*)name >+{ >+ NSString* defaultFilePath = [[NSBundle mainBundle] pathForResource:name ofType:@"whlsl"]; >+ NSString* defaultContents = [NSString stringWithContentsOfFile:defaultFilePath encoding:NSUTF8StringEncoding error:nil]; >+ >+ // Do any additional setup after loading the view. >+ self.whlslTextView.string = defaultContents; >+ self.mslTextView.string = @""; >+ self.metalView.hidden = YES; >+ >+ [self updateHighlighting]; >+} >+ >+- (IBAction)compileClicked:(id)sender { >+ NSError *error = nil; >+ CompileResult *output = [self.compiler compileWhlslToMetal:self.whlslTextView.string error:&error]; >+ if (error) >+ self.mslTextView.string = error.localizedDescription; >+ else { >+ self.metalView.hidden = NO; >+ self.mslTextView.string = output.source; >+ NSString *vertexShaderName = [output defaultInstanceMethodForFunctionName:@"vertexShader"]; >+ NSString *fragmentShaderName = [output defaultInstanceMethodForFunctionName:@"fragmentShader"]; >+ [self viewDidLayout]; >+ [self.renderer setShaderSource:output.source vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName]; >+ [self.metalView setNeedsDisplay:YES]; >+ } >+ self.mslTextView.font = [NSFont fontWithName:@"Menlo" size:12]; >+ >+ [self updateHighlighting]; >+} >+ >+- (IBAction)loadNativeFlatColor:(id)sender >+{ >+ [self loadNativeFlatColor:@"flatColor"]; >+} >+ >+- (IBAction)loadNativeMandelbrot:(id)sender >+{ >+ [self loadNativeMetalShaderWithName:@"mandelbrot"]; >+} >+ >+- (IBAction)loadNativeJulia:(id)sender >+{ >+ [self loadNativeMetalShaderWithName:@"julia"]; >+} >+ >+- (void)loadNativeMetalShaderWithName:(NSString*)name >+{ >+ NSString* vertexShaderName = [name stringByAppendingString:@"VertexShader"]; >+ NSString* fragmentShaderName = [name stringByAppendingString:@"FragmentShader"]; >+ [self viewDidLayout]; >+ [self.renderer setLibrary:self.library vertexShaderName:vertexShaderName fragmentShaderName:fragmentShaderName pixelFormat:self.metalView.colorPixelFormat]; >+ [self.metalView setNeedsDisplay:YES]; >+} >+ >+- (void)updateHighlighting >+{ >+ [self.compiler lexMsl:self.mslTextView.textStorage]; >+ [self.compiler lexWhlsl:self.whlslTextView.textStorage]; >+} >+ >+- (IBAction)zoom:(id)sender >+{ >+ float factor = 1.0f / (1 + self.magnifyGesture.magnification); >+ NSPoint location = [self.magnifyGesture locationInView:self.metalView]; >+ float normalizedX = location.x / CGRectGetWidth(self.metalView.frame); >+ float normalizedY = location.y / CGRectGetHeight(self.metalView.frame); >+ simd_float3 normalized = simd_make_float3(normalizedX, normalizedY, 1); >+ normalized = matrix_multiply(self.renderer.transformMatrix, normalized); >+ simd_float3x3 initTransform = simd_matrix(simd_make_float3(1, 0, 0), >+ simd_make_float3(0, 1, 0), >+ simd_make_float3(-normalized.x, -normalized.y, 1)); >+ simd_float3x3 scaleMatrix = simd_matrix(simd_make_float3(factor, 0.f, 0.f), >+ simd_make_float3(0.f, factor, 0.f), >+ simd_make_float3(0.f, 0.f, 1)); >+ simd_float3x3 backTransform = simd_matrix(simd_make_float3(1, 0, 0), >+ simd_make_float3(0, 1, 0), >+ simd_make_float3(normalized.x, normalized.y, 1)); >+ self.renderer.transformMatrix = matrix_multiply(matrix_multiply(backTransform, matrix_multiply(scaleMatrix, initTransform)), self.renderer.transformMatrix); >+ self.magnifyGesture.magnification = 0; >+ [self.metalView setNeedsDisplay:YES]; >+} >+ >+- (IBAction)rotate:(id)sender >+{ >+ float angle = -self.rotationGesture.rotation; >+ NSPoint location = [self.rotationGesture locationInView:self.metalView]; >+ float normalizedX = location.x / CGRectGetWidth(self.metalView.frame); >+ float normalizedY = location.y / CGRectGetHeight(self.metalView.frame); >+ simd_float3 normalized = simd_make_float3(normalizedX, normalizedY, 1); >+ normalized = matrix_multiply(self.renderer.transformMatrix, normalized); >+ // NSLog(@"%f %f", normalized.x, normalized.y); >+ simd_float3x3 initTransform = simd_matrix(simd_make_float3(1, 0, 0), >+ simd_make_float3(0, 1, 0), >+ simd_make_float3(-normalized.x, -normalized.y, 1)); >+ simd_float3x3 rotationMatrix = simd_matrix(simd_make_float3(cos(angle), sin(angle), 0.f), >+ simd_make_float3(-sin(angle), cos(angle), 0.f), >+ simd_make_float3(0.f, 0.f, 1)); >+ simd_float3x3 backTransform = simd_matrix(simd_make_float3(1, 0, 0), >+ simd_make_float3(0, 1, 0), >+ simd_make_float3(normalized.x, normalized.y, 1)); >+ self.renderer.transformMatrix = matrix_multiply(matrix_multiply(backTransform, matrix_multiply(rotationMatrix, initTransform)), self.renderer.transformMatrix); >+ self.rotationGesture.rotation = 0; >+ [self.metalView setNeedsDisplay:YES]; >+} >+ >+- (void)customMetalView:(CustomMetalView *)metalView scrolledDeltaX:(CGFloat)deltaX deltaY:(CGFloat)deltaY >+{ >+ float width = self.metalView.bounds.size.width; >+ float height = self.metalView.bounds.size.height; >+ float scrollVelocity = 6; >+ float x = -deltaX / width * scrollVelocity; >+ float y = deltaY / height * scrollVelocity; >+ simd_float3x3 m = simd_matrix(simd_make_float3(1, 0, 0), >+ simd_make_float3(0, 1, 0), >+ simd_make_float3(x, y, 1)); >+ self.renderer.transformMatrix = matrix_multiply(self.renderer.transformMatrix, m); >+} >+ >+- (void)textDidChange:(NSNotification *)notification >+{ >+ [self updateHighlighting]; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/WHLSL.entitlements b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/WHLSL.entitlements >new file mode 100644 >index 0000000000000000000000000000000000000000..f2ef3ae0265b40c475e8ef90e3a311c31786c594 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/WHLSL.entitlements >@@ -0,0 +1,10 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> >+<plist version="1.0"> >+<dict> >+ <key>com.apple.security.app-sandbox</key> >+ <true/> >+ <key>com.apple.security.files.user-selected.read-only</key> >+ <true/> >+</dict> >+</plist> >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/_Shared.whlsl b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/_Shared.whlsl >new file mode 100644 >index 0000000000000000000000000000000000000000..2b5dc3618b3fe2e555399105a385cc06a1b7a653 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/_Shared.whlsl >@@ -0,0 +1,12 @@ >+struct VertexInput { float2 position; float2 uv; } >+struct VertexOutput { float4 wsl_Position; } >+struct FragmentOutputFloat { float wsl_Color; } >+struct FragmentOutputInt { int wsl_Color; } >+struct FragmentOutputUint { uint wsl_Color; } >+ >+vertex VertexOutput vertexShader(VertexInput vertexInput) >+{ >+ VertexOutput result; >+ result.wsl_Position = float4(vertexInput.position, 0., 1.); >+ return result; >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/main.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/main.m >new file mode 100644 >index 0000000000000000000000000000000000000000..22bf7ee48b4d29565d0b7256054a624fc5f47994 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/Core/main.m >@@ -0,0 +1,14 @@ >+// >+// main.m >+// WHLSL Toy >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <Cocoa/Cocoa.h> >+ >+int main(int argc, const char * argv[]) >+{ >+ return NSApplicationMain(argc, argv); >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL Tests.xcodeproj/project.pbxproj b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL Tests.xcodeproj/project.pbxproj >new file mode 100644 >index 0000000000000000000000000000000000000000..1dbf60eca9f0286af5cbca3361dad47473d2e1cb >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL Tests.xcodeproj/project.pbxproj >@@ -0,0 +1,1226 @@ >+// !$*UTF8*$! >+{ >+ archiveVersion = 1; >+ classes = { >+ }; >+ objectVersion = 50; >+ objects = { >+ >+/* Begin PBXBuildFile section */ >+ E906B04621139B7700AD1C5E /* Julia.whlsl in Resources */ = {isa = PBXBuildFile; fileRef = E906B04521139B7700AD1C5E /* Julia.whlsl */; }; >+ E9292D8E21127873006130E3 /* SwizzleOp.js in Resources */ = {isa = PBXBuildFile; fileRef = E9292D8D21127873006130E3 /* SwizzleOp.js */; }; >+ E92D108A20F56F0600D776B2 /* Compiler.m in Sources */ = {isa = PBXBuildFile; fileRef = E92D108920F56F0600D776B2 /* Compiler.m */; }; >+ E92D108D20F56F4500D776B2 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E92D108C20F56F4500D776B2 /* MetalKit.framework */; }; >+ E92D108F20F56F4F00D776B2 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E92D108E20F56F4F00D776B2 /* Metal.framework */; }; >+ E92D109120F56F5700D776B2 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E92D109020F56F5700D776B2 /* JavaScriptCore.framework */; }; >+ E92D109320F5734900D776B2 /* Default.whlsl in Resources */ = {isa = PBXBuildFile; fileRef = E92D109220F5734900D776B2 /* Default.whlsl */; }; >+ E92D10AF20F57C9F00D776B2 /* OnscreenRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = E92D10AE20F57C9F00D776B2 /* OnscreenRenderer.m */; }; >+ E92D111520F6FFB600D776B2 /* Renderer.m in Sources */ = {isa = PBXBuildFile; fileRef = E92D111420F6FFB600D776B2 /* Renderer.m */; }; >+ E92D111620F7060E00D776B2 /* AddressSpace.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BA20F56CD600F5CF34 /* AddressSpace.js */; }; >+ E92D111720F7060E00D776B2 /* All.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BC20F56CD700F5CF34 /* All.js */; }; >+ E92D111820F7060E00D776B2 /* AnonymousVariable.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BD20F56CD700F5CF34 /* AnonymousVariable.js */; }; >+ E92D111920F7060E00D776B2 /* ArrayRefType.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B520F56CD600F5CF34 /* ArrayRefType.js */; }; >+ E92D111A20F7060E00D776B2 /* ArrayType.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B420F56CD600F5CF34 /* ArrayType.js */; }; >+ E92D111B20F7060E00D776B2 /* Assignment.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B920F56CD600F5CF34 /* Assignment.js */; }; >+ E92D111C20F7060E00D776B2 /* AutoWrapper.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BE20F56CD700F5CF34 /* AutoWrapper.js */; }; >+ E92D111D20F7060E00D776B2 /* Block.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06FC20F56CA300672992 /* Block.js */; }; >+ E92D111E20F7060E00D776B2 /* BoolLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B120F56CD600F5CF34 /* BoolLiteral.js */; }; >+ E92D111F20F7060E00D776B2 /* Break.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B020F56CD600F5CF34 /* Break.js */; }; >+ E92D112020F7060E00D776B2 /* CallExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BF20F56CD700F5CF34 /* CallExpression.js */; }; >+ E92D112120F7060E00D776B2 /* CallFunction.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569C020F56CD700F5CF34 /* CallFunction.js */; }; >+ E92D112220F7060E00D776B2 /* Check.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B820F56CD600F5CF34 /* Check.js */; }; >+ E92D112320F7060E00D776B2 /* Checker.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569C120F56CD700F5CF34 /* Checker.js */; }; >+ E92D112420F7060E00D776B2 /* CheckLiteralTypes.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B620F56CD600F5CF34 /* CheckLiteralTypes.js */; }; >+ E92D112520F7060E00D776B2 /* CheckLoops.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B320F56CD600F5CF34 /* CheckLoops.js */; }; >+ E92D112620F7060E00D776B2 /* CheckRecursion.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06FA20F56CA300672992 /* CheckRecursion.js */; }; >+ E92D112720F7060E00D776B2 /* CheckRecursiveTypes.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569BB20F56CD600F5CF34 /* CheckRecursiveTypes.js */; }; >+ E92D112820F7060E00D776B2 /* CheckReturns.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B220F56CD600F5CF34 /* CheckReturns.js */; }; >+ E92D112920F7060E00D776B2 /* CheckUnreachableCode.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569B720F56CD600F5CF34 /* CheckUnreachableCode.js */; }; >+ E92D112A20F7060E00D776B2 /* CheckWrapped.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D420F56CED00F5CF34 /* CheckWrapped.js */; }; >+ E92D112B20F7060E00D776B2 /* CloneProgram.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569DB20F56CEE00F5CF34 /* CloneProgram.js */; }; >+ E92D112C20F7060E00D776B2 /* CommaExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569DC20F56CEE00F5CF34 /* CommaExpression.js */; }; >+ E92D112D20F7060E00D776B2 /* compiler.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06F720F56C6000672992 /* compiler.js */; }; >+ E92D112E20F7060E00D776B2 /* ConstexprFolder.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D520F56CED00F5CF34 /* ConstexprFolder.js */; }; >+ E92D112F20F7060E00D776B2 /* ConstexprTypeParameter.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569DA20F56CED00F5CF34 /* ConstexprTypeParameter.js */; }; >+ E92D113020F7060E00D776B2 /* Continue.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D720F56CED00F5CF34 /* Continue.js */; }; >+ E92D113120F7060E00D776B2 /* ConvertPtrToArrayRefExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D920F56CED00F5CF34 /* ConvertPtrToArrayRefExpression.js */; }; >+ E92D113220F7060E00D776B2 /* CreateLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D820F56CED00F5CF34 /* CreateLiteral.js */; }; >+ E92D113320F7060E00D776B2 /* CreateLiteralType.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569D620F56CED00F5CF34 /* CreateLiteralType.js */; }; >+ E92D113420F7060E00D776B2 /* DereferenceExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06F920F56CA300672992 /* DereferenceExpression.js */; }; >+ E92D113520F7060E00D776B2 /* DotExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD074B20F56D5B007F2466 /* DotExpression.js */; }; >+ E92D113820F7060E00D776B2 /* DoWhileLoop.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD074620F56D5A007F2466 /* DoWhileLoop.js */; }; >+ E92D113920F7060E00D776B2 /* EArrayRef.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD074920F56D5A007F2466 /* EArrayRef.js */; }; >+ E92D113A20F7060E00D776B2 /* EBuffer.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD074820F56D5A007F2466 /* EBuffer.js */; }; >+ E92D113B20F7060E00D776B2 /* EBufferBuilder.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD074A20F56D5B007F2466 /* EBufferBuilder.js */; }; >+ E92D113C20F7060E00D776B2 /* EnumLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06FD20F56CA300672992 /* EnumLiteral.js */; }; >+ E92D113D20F7060E00D776B2 /* EnumMember.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075520F56D69007F2466 /* EnumMember.js */; }; >+ E92D113E20F7060E00D776B2 /* EnumType.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075A20F56D69007F2466 /* EnumType.js */; }; >+ E92D113F20F7060E00D776B2 /* EPtr.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569E720F56D0500F5CF34 /* EPtr.js */; }; >+ E92D114020F7060E00D776B2 /* EvaluationCommon.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075320F56D69007F2466 /* EvaluationCommon.js */; }; >+ E92D114120F7060E00D776B2 /* Evaluator.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075720F56D69007F2466 /* Evaluator.js */; }; >+ E92D114220F7060E00D776B2 /* Expression.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075420F56D69007F2466 /* Expression.js */; }; >+ E92D114320F7060E00D776B2 /* ExpressionFinder.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075920F56D69007F2466 /* ExpressionFinder.js */; }; >+ E92D114420F7060E00D776B2 /* ExternalOrigin.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075B20F56D69007F2466 /* ExternalOrigin.js */; }; >+ E92D114520F7060E00D776B2 /* Field.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5B20F56D93009B3629 /* Field.js */; }; >+ E92D114620F7060E00D776B2 /* FindHighZombies.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075820F56D69007F2466 /* FindHighZombies.js */; }; >+ E92D114720F7060E00D776B2 /* FlattenedStructOffsetGatherer.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075620F56D69007F2466 /* FlattenedStructOffsetGatherer.js */; }; >+ E92D114820F7060E00D776B2 /* FlattenProtocolExtends.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5920F56D93009B3629 /* FlattenProtocolExtends.js */; }; >+ E92D114920F7060E00D776B2 /* FloatLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E9AD075C20F56D69007F2466 /* FloatLiteral.js */; }; >+ E92D114A20F7060E00D776B2 /* FloatLiteralType.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569EA20F56D0500F5CF34 /* FloatLiteralType.js */; }; >+ E92D114B20F7060E00D776B2 /* FoldConstexprs.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569EB20F56D0500F5CF34 /* FoldConstexprs.js */; }; >+ E92D114C20F7060E00D776B2 /* ForLoop.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5A20F56D93009B3629 /* ForLoop.js */; }; >+ E92D114D20F7060E00D776B2 /* Func.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5520F56D92009B3629 /* Func.js */; }; >+ E92D114E20F7060E00D776B2 /* FuncDef.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569E820F56D0500F5CF34 /* FuncDef.js */; }; >+ E92D114F20F7060E00D776B2 /* FuncInstantiator.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5620F56D92009B3629 /* FuncInstantiator.js */; }; >+ E92D115020F7060E00D776B2 /* FuncParameter.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569E920F56D0500F5CF34 /* FuncParameter.js */; }; >+ E92D115120F7060E00D776B2 /* FunctionLikeBlock.js in Resources */ = {isa = PBXBuildFile; fileRef = E95569E620F56D0500F5CF34 /* FunctionLikeBlock.js */; }; >+ E92D115220F7060E00D776B2 /* HighZombieFinder.js in Resources */ = {isa = PBXBuildFile; fileRef = E94C06FB20F56CA300672992 /* HighZombieFinder.js */; }; >+ E92D115320F7060E00D776B2 /* IdentityExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5820F56D93009B3629 /* IdentityExpression.js */; }; >+ E92D115420F7060E00D776B2 /* IfStatement.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB5720F56D93009B3629 /* IfStatement.js */; }; >+ E92D115520F7060E00D776B2 /* IndexExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB6320F56DA4009B3629 /* IndexExpression.js */; }; >+ E92D115620F7060E00D776B2 /* InferTypesForCall.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB6520F56DA5009B3629 /* InferTypesForCall.js */; }; >+ E92D115720F7060E00D776B2 /* Inline.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB6620F56DA5009B3629 /* Inline.js */; }; >+ E92D115820F7060E00D776B2 /* Inliner.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FE820F56DDD00D776B2 /* Inliner.js */; }; >+ E92D115920F7060E00D776B2 /* InstantiateImmediates.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FE620F56DDD00D776B2 /* InstantiateImmediates.js */; }; >+ E92D115A20F7060E00D776B2 /* IntLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FE420F56DDD00D776B2 /* IntLiteral.js */; }; >+ E92D115B20F7060E00D776B2 /* IntLiteralType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FE520F56DDD00D776B2 /* IntLiteralType.js */; }; >+ E92D115C20F7060E00D776B2 /* Intrinsics.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FE720F56DDD00D776B2 /* Intrinsics.js */; }; >+ E92D115D20F7060E00D776B2 /* LateChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E9FCEB6420F56DA5009B3629 /* LateChecker.js */; }; >+ E92D115E20F7060E00D776B2 /* Lexer.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FF120F56DEC00D776B2 /* Lexer.js */; }; >+ E92D115F20F7060E00D776B2 /* LexerToken.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FF020F56DEB00D776B2 /* LexerToken.js */; }; >+ E92D116020F7060E00D776B2 /* LiteralTypeChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FF220F56DEC00D776B2 /* LiteralTypeChecker.js */; }; >+ E92D116120F7060E00D776B2 /* LogicalExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FEE20F56DEB00D776B2 /* LogicalExpression.js */; }; >+ E92D116220F7060E00D776B2 /* LogicalNot.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FEF20F56DEB00D776B2 /* LogicalNot.js */; }; >+ E92D116320F7060E00D776B2 /* LoopChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FFB20F56DFB00D776B2 /* LoopChecker.js */; }; >+ E92D116420F7060E00D776B2 /* MakeArrayRefExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FFC20F56DFB00D776B2 /* MakeArrayRefExpression.js */; }; >+ E92D116520F7060E00D776B2 /* MakePtrExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FF920F56DFA00D776B2 /* MakePtrExpression.js */; }; >+ E92D116620F7060E00D776B2 /* NameContext.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FF820F56DFA00D776B2 /* NameContext.js */; }; >+ E92D116720F7060E00D776B2 /* NameFinder.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D0FFA20F56DFB00D776B2 /* NameFinder.js */; }; >+ E92D116820F7060E00D776B2 /* NameResolver.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100320F56E0900D776B2 /* NameResolver.js */; }; >+ E92D116920F7060E00D776B2 /* NativeFunc.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100520F56E0900D776B2 /* NativeFunc.js */; }; >+ E92D116A20F7060E00D776B2 /* NativeFuncInstance.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100420F56E0900D776B2 /* NativeFuncInstance.js */; }; >+ E92D116B20F7060E00D776B2 /* NativeType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100620F56E0900D776B2 /* NativeType.js */; }; >+ E92D116C20F7060E00D776B2 /* NativeTypeInstance.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100220F56E0800D776B2 /* NativeTypeInstance.js */; }; >+ E92D116D20F7060E00D776B2 /* Node.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100F20F56E1500D776B2 /* Node.js */; }; >+ E92D116E20F7060E00D776B2 /* NormalUsePropertyResolver.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100D20F56E1500D776B2 /* NormalUsePropertyResolver.js */; }; >+ E92D116F20F7060E00D776B2 /* NullLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100C20F56E1500D776B2 /* NullLiteral.js */; }; >+ E92D117020F7060E00D776B2 /* NullType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101020F56E1500D776B2 /* NullType.js */; }; >+ E92D117120F7060E00D776B2 /* OriginKind.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D100E20F56E1500D776B2 /* OriginKind.js */; }; >+ E92D117220F7060E00D776B2 /* OverloadResolutionFailure.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101920F56E2200D776B2 /* OverloadResolutionFailure.js */; }; >+ E92D117320F7060E00D776B2 /* Parse.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101720F56E2200D776B2 /* Parse.js */; }; >+ E92D117420F7060E00D776B2 /* Prepare.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101820F56E2200D776B2 /* Prepare.js */; }; >+ E92D117520F7060E00D776B2 /* Program.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101A20F56E2200D776B2 /* Program.js */; }; >+ E92D117620F7060E00D776B2 /* ProgramWithUnnecessaryThingsRemoved.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D101620F56E2100D776B2 /* ProgramWithUnnecessaryThingsRemoved.js */; }; >+ E92D117720F7060E00D776B2 /* PropertyAccessExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102320F56E2F00D776B2 /* PropertyAccessExpression.js */; }; >+ E92D117820F7060E00D776B2 /* PropertyResolver.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102020F56E2F00D776B2 /* PropertyResolver.js */; }; >+ E92D117920F7060E00D776B2 /* Protocol.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102120F56E2F00D776B2 /* Protocol.js */; }; >+ E92D117A20F7060E00D776B2 /* ProtocolDecl.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102420F56E3000D776B2 /* ProtocolDecl.js */; }; >+ E92D117B20F7060E00D776B2 /* ProtocolFuncDecl.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102220F56E2F00D776B2 /* ProtocolFuncDecl.js */; }; >+ E92D117C20F7060E00D776B2 /* ProtocolRef.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102D20F56E4000D776B2 /* ProtocolRef.js */; }; >+ E92D117D20F7060E00D776B2 /* PtrType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102B20F56E3F00D776B2 /* PtrType.js */; }; >+ E92D117E20F7060E00D776B2 /* ReadModifyWriteExpression.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102A20F56E3F00D776B2 /* ReadModifyWriteExpression.js */; }; >+ E92D117F20F7060E00D776B2 /* RecursionChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102C20F56E3F00D776B2 /* RecursionChecker.js */; }; >+ E92D118020F7060E00D776B2 /* RecursiveTypeChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D102E20F56E4000D776B2 /* RecursiveTypeChecker.js */; }; >+ E92D118120F7060E00D776B2 /* ReferenceType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103520F56E4F00D776B2 /* ReferenceType.js */; }; >+ E92D118220F7060E00D776B2 /* ResolveNames.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103420F56E4F00D776B2 /* ResolveNames.js */; }; >+ E92D118320F7060E00D776B2 /* ResolveOverloadImpl.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103820F56E4F00D776B2 /* ResolveOverloadImpl.js */; }; >+ E92D118420F7060E00D776B2 /* ResolveProperties.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103620F56E4F00D776B2 /* ResolveProperties.js */; }; >+ E92D118520F7060E00D776B2 /* ResolveTypeDefs.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103720F56E4F00D776B2 /* ResolveTypeDefs.js */; }; >+ E92D118620F7060E00D776B2 /* Return.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103E20F56E6100D776B2 /* Return.js */; }; >+ E92D118720F7060E00D776B2 /* ReturnChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104020F56E6200D776B2 /* ReturnChecker.js */; }; >+ E92D118820F7060E00D776B2 /* ReturnException.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104220F56E6200D776B2 /* ReturnException.js */; }; >+ E92D118920F7060E00D776B2 /* Rewriter.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104120F56E6200D776B2 /* Rewriter.js */; }; >+ E92D118A20F7060E00D776B2 /* StandardLibrary.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D103F20F56E6200D776B2 /* StandardLibrary.js */; }; >+ E92D118B20F7060E00D776B2 /* StatementCloner.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104820F56E7300D776B2 /* StatementCloner.js */; }; >+ E92D118C20F7060E00D776B2 /* StructLayoutBuilder.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104920F56E7300D776B2 /* StructLayoutBuilder.js */; }; >+ E92D118D20F7060E00D776B2 /* StructType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104A20F56E7300D776B2 /* StructType.js */; }; >+ E92D118E20F7060E00D776B2 /* Substitution.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104C20F56E7300D776B2 /* Substitution.js */; }; >+ E92D118F20F7060E00D776B2 /* SwitchCase.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D104B20F56E7300D776B2 /* SwitchCase.js */; }; >+ E92D119020F7060E00D776B2 /* SwitchStatement.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105220F56E8400D776B2 /* SwitchStatement.js */; }; >+ E92D119120F7060E00D776B2 /* SynthesizeEnumFunctions.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105420F56E8500D776B2 /* SynthesizeEnumFunctions.js */; }; >+ E92D119220F7060E00D776B2 /* SynthesizeStructAccessors.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105320F56E8400D776B2 /* SynthesizeStructAccessors.js */; }; >+ E92D119320F7060E00D776B2 /* TrapStatement.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105620F56E8500D776B2 /* TrapStatement.js */; }; >+ E92D119420F7060E00D776B2 /* Type.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105520F56E8500D776B2 /* Type.js */; }; >+ E92D119520F7060E00D776B2 /* TypeDef.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105F20F56E9500D776B2 /* TypeDef.js */; }; >+ E92D119620F7060E00D776B2 /* TypeDefResolver.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105E20F56E9500D776B2 /* TypeDefResolver.js */; }; >+ E92D119720F7060E00D776B2 /* TypedValue.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D106020F56E9500D776B2 /* TypedValue.js */; }; >+ E92D119820F7060E00D776B2 /* TypeOrVariableRef.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105D20F56E9500D776B2 /* TypeOrVariableRef.js */; }; >+ E92D119920F7060E00D776B2 /* TypeParameterRewriter.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D105C20F56E9400D776B2 /* TypeParameterRewriter.js */; }; >+ E92D119A20F7060E00D776B2 /* TypeRef.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D106620F56EA400D776B2 /* TypeRef.js */; }; >+ E92D119B20F7060E00D776B2 /* TypeVariable.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D106A20F56EA500D776B2 /* TypeVariable.js */; }; >+ E92D119C20F7060E00D776B2 /* TypeVariableTracker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D106920F56EA500D776B2 /* TypeVariableTracker.js */; }; >+ E92D119D20F7060E00D776B2 /* UintLiteral.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D106820F56EA400D776B2 /* UintLiteral.js */; }; >+ E92D119E20F7060E00D776B2 /* UintLiteralType.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D106720F56EA400D776B2 /* UintLiteralType.js */; }; >+ E92D119F20F7060E00D776B2 /* UnificationContext.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107220F56EBB00D776B2 /* UnificationContext.js */; }; >+ E92D11A020F7060E00D776B2 /* UnreachableCodeChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107320F56EBC00D776B2 /* UnreachableCodeChecker.js */; }; >+ E92D11A120F7060E00D776B2 /* Value.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107420F56EBC00D776B2 /* Value.js */; }; >+ E92D11A220F7060E00D776B2 /* VariableDecl.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107020F56EBB00D776B2 /* VariableDecl.js */; }; >+ E92D11A320F7060E00D776B2 /* VariableRef.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107120F56EBB00D776B2 /* VariableRef.js */; }; >+ E92D11A420F7060E00D776B2 /* VisitingSet.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107C20F56ECF00D776B2 /* VisitingSet.js */; }; >+ E92D11A520F7060E00D776B2 /* Visitor.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107A20F56ECF00D776B2 /* Visitor.js */; }; >+ E92D11A620F7060E00D776B2 /* WhileLoop.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107D20F56ECF00D776B2 /* WhileLoop.js */; }; >+ E92D11A720F7060E00D776B2 /* WrapChecker.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D107B20F56ECF00D776B2 /* WrapChecker.js */; }; >+ E92D11A820F7060E00D776B2 /* WSyntaxError.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D108220F56EDE00D776B2 /* WSyntaxError.js */; }; >+ E92D11A920F7060E00D776B2 /* WTrapError.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D108420F56EDE00D776B2 /* WTrapError.js */; }; >+ E92D11AA20F7060E00D776B2 /* WTypeError.js in Resources */ = {isa = PBXBuildFile; fileRef = E92D108320F56EDE00D776B2 /* WTypeError.js */; }; >+ E92D11AD20F7081500D776B2 /* OffscreenRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = E92D11AC20F7081500D776B2 /* OffscreenRenderer.m */; }; >+ E92D11BB20F7F67300D776B2 /* CompileResult.m in Sources */ = {isa = PBXBuildFile; fileRef = E92D11BA20F7F67300D776B2 /* CompileResult.m */; }; >+ E92EDFFB211546A40042F960 /* CustomMetalView.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EDFF6211546A40042F960 /* CustomMetalView.m */; }; >+ E92EDFFC211546A40042F960 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EDFF7211546A40042F960 /* AppDelegate.m */; }; >+ E92EDFFD211546A40042F960 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EDFFA211546A40042F960 /* ViewController.m */; }; >+ E92EE000211546AB0042F960 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E92EDFFE211546AB0042F960 /* Main.storyboard */; }; >+ E92EE004211549C50042F960 /* TestCallArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EE003211549C50042F960 /* TestCallArgument.m */; }; >+ E92EE00721154AC40042F960 /* TestFamily.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EE00621154AC40042F960 /* TestFamily.m */; }; >+ E92EE00A21154B5A0042F960 /* TestDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EE00921154B5A0042F960 /* TestDescription.m */; }; >+ E92EE00C211554980042F960 /* _Shared.whlsl in Resources */ = {isa = PBXBuildFile; fileRef = E92EE00B211554980042F960 /* _Shared.whlsl */; }; >+ E92EE00F211563300042F960 /* TestFamilyRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = E92EE00E211563300042F960 /* TestFamilyRunner.m */; }; >+ E94C06CA20F56A4200672992 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E94C06C920F56A4200672992 /* Assets.xcassets */; }; >+ E94C06D020F56A4200672992 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E94C06CF20F56A4200672992 /* main.m */; }; >+ E94C06DB20F56A4200672992 /* WHLSL_ToyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E94C06DA20F56A4200672992 /* WHLSL_ToyTests.m */; }; >+ E94D124F2114BD7600B0F967 /* Mandelbrot.whlsl in Resources */ = {isa = PBXBuildFile; fileRef = E94D124E2114BD7600B0F967 /* Mandelbrot.whlsl */; }; >+ E94D127F2114C6FF00B0F967 /* Test.js in Resources */ = {isa = PBXBuildFile; fileRef = E94D127E2114C6FF00B0F967 /* Test.js */; }; >+ E9E11933211E61640014D553 /* Shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = E9E11932211E61640014D553 /* Shaders.metal */; }; >+/* End PBXBuildFile section */ >+ >+/* Begin PBXContainerItemProxy section */ >+ E94C06D720F56A4200672992 /* PBXContainerItemProxy */ = { >+ isa = PBXContainerItemProxy; >+ containerPortal = E94C06B820F56A4000672992 /* Project object */; >+ proxyType = 1; >+ remoteGlobalIDString = E94C06BF20F56A4000672992; >+ remoteInfo = "WHLSL Toy"; >+ }; >+/* End PBXContainerItemProxy section */ >+ >+/* Begin PBXFileReference section */ >+ E906B04521139B7700AD1C5E /* Julia.whlsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Julia.whlsl; sourceTree = "<group>"; }; >+ E9292D8D21127873006130E3 /* SwizzleOp.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SwizzleOp.js; path = ../../../SwizzleOp.js; sourceTree = "<group>"; }; >+ E92D0FE420F56DDD00D776B2 /* IntLiteral.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = IntLiteral.js; path = ../../../IntLiteral.js; sourceTree = "<group>"; }; >+ E92D0FE520F56DDD00D776B2 /* IntLiteralType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = IntLiteralType.js; path = ../../../IntLiteralType.js; sourceTree = "<group>"; }; >+ E92D0FE620F56DDD00D776B2 /* InstantiateImmediates.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = InstantiateImmediates.js; path = ../../../InstantiateImmediates.js; sourceTree = "<group>"; }; >+ E92D0FE720F56DDD00D776B2 /* Intrinsics.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Intrinsics.js; path = ../../../Intrinsics.js; sourceTree = "<group>"; }; >+ E92D0FE820F56DDD00D776B2 /* Inliner.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Inliner.js; path = ../../../Inliner.js; sourceTree = "<group>"; }; >+ E92D0FEE20F56DEB00D776B2 /* LogicalExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = LogicalExpression.js; path = ../../../LogicalExpression.js; sourceTree = "<group>"; }; >+ E92D0FEF20F56DEB00D776B2 /* LogicalNot.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = LogicalNot.js; path = ../../../LogicalNot.js; sourceTree = "<group>"; }; >+ E92D0FF020F56DEB00D776B2 /* LexerToken.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = LexerToken.js; path = ../../../LexerToken.js; sourceTree = "<group>"; }; >+ E92D0FF120F56DEC00D776B2 /* Lexer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Lexer.js; path = ../../../Lexer.js; sourceTree = "<group>"; }; >+ E92D0FF220F56DEC00D776B2 /* LiteralTypeChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = LiteralTypeChecker.js; path = ../../../LiteralTypeChecker.js; sourceTree = "<group>"; }; >+ E92D0FF820F56DFA00D776B2 /* NameContext.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NameContext.js; path = ../../../NameContext.js; sourceTree = "<group>"; }; >+ E92D0FF920F56DFA00D776B2 /* MakePtrExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = MakePtrExpression.js; path = ../../../MakePtrExpression.js; sourceTree = "<group>"; }; >+ E92D0FFA20F56DFB00D776B2 /* NameFinder.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NameFinder.js; path = ../../../NameFinder.js; sourceTree = "<group>"; }; >+ E92D0FFB20F56DFB00D776B2 /* LoopChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = LoopChecker.js; path = ../../../LoopChecker.js; sourceTree = "<group>"; }; >+ E92D0FFC20F56DFB00D776B2 /* MakeArrayRefExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = MakeArrayRefExpression.js; path = ../../../MakeArrayRefExpression.js; sourceTree = "<group>"; }; >+ E92D100220F56E0800D776B2 /* NativeTypeInstance.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NativeTypeInstance.js; path = ../../../NativeTypeInstance.js; sourceTree = "<group>"; }; >+ E92D100320F56E0900D776B2 /* NameResolver.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NameResolver.js; path = ../../../NameResolver.js; sourceTree = "<group>"; }; >+ E92D100420F56E0900D776B2 /* NativeFuncInstance.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NativeFuncInstance.js; path = ../../../NativeFuncInstance.js; sourceTree = "<group>"; }; >+ E92D100520F56E0900D776B2 /* NativeFunc.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NativeFunc.js; path = ../../../NativeFunc.js; sourceTree = "<group>"; }; >+ E92D100620F56E0900D776B2 /* NativeType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NativeType.js; path = ../../../NativeType.js; sourceTree = "<group>"; }; >+ E92D100C20F56E1500D776B2 /* NullLiteral.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NullLiteral.js; path = ../../../NullLiteral.js; sourceTree = "<group>"; }; >+ E92D100D20F56E1500D776B2 /* NormalUsePropertyResolver.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NormalUsePropertyResolver.js; path = ../../../NormalUsePropertyResolver.js; sourceTree = "<group>"; }; >+ E92D100E20F56E1500D776B2 /* OriginKind.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = OriginKind.js; path = ../../../OriginKind.js; sourceTree = "<group>"; }; >+ E92D100F20F56E1500D776B2 /* Node.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Node.js; path = ../../../Node.js; sourceTree = "<group>"; }; >+ E92D101020F56E1500D776B2 /* NullType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = NullType.js; path = ../../../NullType.js; sourceTree = "<group>"; }; >+ E92D101620F56E2100D776B2 /* ProgramWithUnnecessaryThingsRemoved.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ProgramWithUnnecessaryThingsRemoved.js; path = ../../../ProgramWithUnnecessaryThingsRemoved.js; sourceTree = "<group>"; }; >+ E92D101720F56E2200D776B2 /* Parse.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Parse.js; path = ../../../Parse.js; sourceTree = "<group>"; }; >+ E92D101820F56E2200D776B2 /* Prepare.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Prepare.js; path = ../../../Prepare.js; sourceTree = "<group>"; }; >+ E92D101920F56E2200D776B2 /* OverloadResolutionFailure.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = OverloadResolutionFailure.js; path = ../../../OverloadResolutionFailure.js; sourceTree = "<group>"; }; >+ E92D101A20F56E2200D776B2 /* Program.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Program.js; path = ../../../Program.js; sourceTree = "<group>"; }; >+ E92D102020F56E2F00D776B2 /* PropertyResolver.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = PropertyResolver.js; path = ../../../PropertyResolver.js; sourceTree = "<group>"; }; >+ E92D102120F56E2F00D776B2 /* Protocol.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Protocol.js; path = ../../../Protocol.js; sourceTree = "<group>"; }; >+ E92D102220F56E2F00D776B2 /* ProtocolFuncDecl.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ProtocolFuncDecl.js; path = ../../../ProtocolFuncDecl.js; sourceTree = "<group>"; }; >+ E92D102320F56E2F00D776B2 /* PropertyAccessExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = PropertyAccessExpression.js; path = ../../../PropertyAccessExpression.js; sourceTree = "<group>"; }; >+ E92D102420F56E3000D776B2 /* ProtocolDecl.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ProtocolDecl.js; path = ../../../ProtocolDecl.js; sourceTree = "<group>"; }; >+ E92D102A20F56E3F00D776B2 /* ReadModifyWriteExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ReadModifyWriteExpression.js; path = ../../../ReadModifyWriteExpression.js; sourceTree = "<group>"; }; >+ E92D102B20F56E3F00D776B2 /* PtrType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = PtrType.js; path = ../../../PtrType.js; sourceTree = "<group>"; }; >+ E92D102C20F56E3F00D776B2 /* RecursionChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = RecursionChecker.js; path = ../../../RecursionChecker.js; sourceTree = "<group>"; }; >+ E92D102D20F56E4000D776B2 /* ProtocolRef.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ProtocolRef.js; path = ../../../ProtocolRef.js; sourceTree = "<group>"; }; >+ E92D102E20F56E4000D776B2 /* RecursiveTypeChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = RecursiveTypeChecker.js; path = ../../../RecursiveTypeChecker.js; sourceTree = "<group>"; }; >+ E92D103420F56E4F00D776B2 /* ResolveNames.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ResolveNames.js; path = ../../../ResolveNames.js; sourceTree = "<group>"; }; >+ E92D103520F56E4F00D776B2 /* ReferenceType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ReferenceType.js; path = ../../../ReferenceType.js; sourceTree = "<group>"; }; >+ E92D103620F56E4F00D776B2 /* ResolveProperties.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ResolveProperties.js; path = ../../../ResolveProperties.js; sourceTree = "<group>"; }; >+ E92D103720F56E4F00D776B2 /* ResolveTypeDefs.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ResolveTypeDefs.js; path = ../../../ResolveTypeDefs.js; sourceTree = "<group>"; }; >+ E92D103820F56E4F00D776B2 /* ResolveOverloadImpl.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ResolveOverloadImpl.js; path = ../../../ResolveOverloadImpl.js; sourceTree = "<group>"; }; >+ E92D103E20F56E6100D776B2 /* Return.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Return.js; path = ../../../Return.js; sourceTree = "<group>"; }; >+ E92D103F20F56E6200D776B2 /* StandardLibrary.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = StandardLibrary.js; path = ../../../StandardLibrary.js; sourceTree = "<group>"; }; >+ E92D104020F56E6200D776B2 /* ReturnChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ReturnChecker.js; path = ../../../ReturnChecker.js; sourceTree = "<group>"; }; >+ E92D104120F56E6200D776B2 /* Rewriter.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Rewriter.js; path = ../../../Rewriter.js; sourceTree = "<group>"; }; >+ E92D104220F56E6200D776B2 /* ReturnException.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ReturnException.js; path = ../../../ReturnException.js; sourceTree = "<group>"; }; >+ E92D104820F56E7300D776B2 /* StatementCloner.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = StatementCloner.js; path = ../../../StatementCloner.js; sourceTree = "<group>"; }; >+ E92D104920F56E7300D776B2 /* StructLayoutBuilder.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = StructLayoutBuilder.js; path = ../../../StructLayoutBuilder.js; sourceTree = "<group>"; }; >+ E92D104A20F56E7300D776B2 /* StructType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = StructType.js; path = ../../../StructType.js; sourceTree = "<group>"; }; >+ E92D104B20F56E7300D776B2 /* SwitchCase.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SwitchCase.js; path = ../../../SwitchCase.js; sourceTree = "<group>"; }; >+ E92D104C20F56E7300D776B2 /* Substitution.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Substitution.js; path = ../../../Substitution.js; sourceTree = "<group>"; }; >+ E92D105220F56E8400D776B2 /* SwitchStatement.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SwitchStatement.js; path = ../../../SwitchStatement.js; sourceTree = "<group>"; }; >+ E92D105320F56E8400D776B2 /* SynthesizeStructAccessors.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SynthesizeStructAccessors.js; path = ../../../SynthesizeStructAccessors.js; sourceTree = "<group>"; }; >+ E92D105420F56E8500D776B2 /* SynthesizeEnumFunctions.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = SynthesizeEnumFunctions.js; path = ../../../SynthesizeEnumFunctions.js; sourceTree = "<group>"; }; >+ E92D105520F56E8500D776B2 /* Type.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Type.js; path = ../../../Type.js; sourceTree = "<group>"; }; >+ E92D105620F56E8500D776B2 /* TrapStatement.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TrapStatement.js; path = ../../../TrapStatement.js; sourceTree = "<group>"; }; >+ E92D105C20F56E9400D776B2 /* TypeParameterRewriter.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeParameterRewriter.js; path = ../../../TypeParameterRewriter.js; sourceTree = "<group>"; }; >+ E92D105D20F56E9500D776B2 /* TypeOrVariableRef.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeOrVariableRef.js; path = ../../../TypeOrVariableRef.js; sourceTree = "<group>"; }; >+ E92D105E20F56E9500D776B2 /* TypeDefResolver.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeDefResolver.js; path = ../../../TypeDefResolver.js; sourceTree = "<group>"; }; >+ E92D105F20F56E9500D776B2 /* TypeDef.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeDef.js; path = ../../../TypeDef.js; sourceTree = "<group>"; }; >+ E92D106020F56E9500D776B2 /* TypedValue.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypedValue.js; path = ../../../TypedValue.js; sourceTree = "<group>"; }; >+ E92D106620F56EA400D776B2 /* TypeRef.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeRef.js; path = ../../../TypeRef.js; sourceTree = "<group>"; }; >+ E92D106720F56EA400D776B2 /* UintLiteralType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = UintLiteralType.js; path = ../../../UintLiteralType.js; sourceTree = "<group>"; }; >+ E92D106820F56EA400D776B2 /* UintLiteral.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = UintLiteral.js; path = ../../../UintLiteral.js; sourceTree = "<group>"; }; >+ E92D106920F56EA500D776B2 /* TypeVariableTracker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeVariableTracker.js; path = ../../../TypeVariableTracker.js; sourceTree = "<group>"; }; >+ E92D106A20F56EA500D776B2 /* TypeVariable.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypeVariable.js; path = ../../../TypeVariable.js; sourceTree = "<group>"; }; >+ E92D107020F56EBB00D776B2 /* VariableDecl.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = VariableDecl.js; path = ../../../VariableDecl.js; sourceTree = "<group>"; }; >+ E92D107120F56EBB00D776B2 /* VariableRef.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = VariableRef.js; path = ../../../VariableRef.js; sourceTree = "<group>"; }; >+ E92D107220F56EBB00D776B2 /* UnificationContext.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = UnificationContext.js; path = ../../../UnificationContext.js; sourceTree = "<group>"; }; >+ E92D107320F56EBC00D776B2 /* UnreachableCodeChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = UnreachableCodeChecker.js; path = ../../../UnreachableCodeChecker.js; sourceTree = "<group>"; }; >+ E92D107420F56EBC00D776B2 /* Value.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Value.js; path = ../../../Value.js; sourceTree = "<group>"; }; >+ E92D107A20F56ECF00D776B2 /* Visitor.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Visitor.js; path = ../../../Visitor.js; sourceTree = "<group>"; }; >+ E92D107B20F56ECF00D776B2 /* WrapChecker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WrapChecker.js; path = ../../../WrapChecker.js; sourceTree = "<group>"; }; >+ E92D107C20F56ECF00D776B2 /* VisitingSet.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = VisitingSet.js; path = ../../../VisitingSet.js; sourceTree = "<group>"; }; >+ E92D107D20F56ECF00D776B2 /* WhileLoop.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WhileLoop.js; path = ../../../WhileLoop.js; sourceTree = "<group>"; }; >+ E92D108220F56EDE00D776B2 /* WSyntaxError.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WSyntaxError.js; path = ../../../WSyntaxError.js; sourceTree = "<group>"; }; >+ E92D108320F56EDE00D776B2 /* WTypeError.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WTypeError.js; path = ../../../WTypeError.js; sourceTree = "<group>"; }; >+ E92D108420F56EDE00D776B2 /* WTrapError.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = WTrapError.js; path = ../../../WTrapError.js; sourceTree = "<group>"; }; >+ E92D108820F56F0600D776B2 /* Compiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Compiler.h; sourceTree = "<group>"; }; >+ E92D108920F56F0600D776B2 /* Compiler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Compiler.m; sourceTree = "<group>"; }; >+ E92D108C20F56F4500D776B2 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; >+ E92D108E20F56F4F00D776B2 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; >+ E92D109020F56F5700D776B2 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; >+ E92D109220F5734900D776B2 /* Default.whlsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Default.whlsl; sourceTree = "<group>"; }; >+ E92D10AD20F57C9F00D776B2 /* OnscreenRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OnscreenRenderer.h; sourceTree = "<group>"; }; >+ E92D10AE20F57C9F00D776B2 /* OnscreenRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OnscreenRenderer.m; sourceTree = "<group>"; }; >+ E92D111320F6FFB600D776B2 /* Renderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Renderer.h; sourceTree = "<group>"; }; >+ E92D111420F6FFB600D776B2 /* Renderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Renderer.m; sourceTree = "<group>"; }; >+ E92D11AB20F7081500D776B2 /* OffscreenRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OffscreenRenderer.h; sourceTree = "<group>"; }; >+ E92D11AC20F7081500D776B2 /* OffscreenRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OffscreenRenderer.m; sourceTree = "<group>"; }; >+ E92D11B920F7F67300D776B2 /* CompileResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CompileResult.h; sourceTree = "<group>"; }; >+ E92D11BA20F7F67300D776B2 /* CompileResult.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CompileResult.m; sourceTree = "<group>"; }; >+ E92EDFF5211546A40042F960 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; >+ E92EDFF6211546A40042F960 /* CustomMetalView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomMetalView.m; sourceTree = "<group>"; }; >+ E92EDFF7211546A40042F960 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; >+ E92EDFF8211546A40042F960 /* CustomMetalView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomMetalView.h; sourceTree = "<group>"; }; >+ E92EDFF9211546A40042F960 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; }; >+ E92EDFFA211546A40042F960 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; }; >+ E92EDFFF211546AB0042F960 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; >+ E92EE002211549C50042F960 /* TestCallArgument.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestCallArgument.h; sourceTree = "<group>"; }; >+ E92EE003211549C50042F960 /* TestCallArgument.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestCallArgument.m; sourceTree = "<group>"; }; >+ E92EE00521154AC40042F960 /* TestFamily.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestFamily.h; sourceTree = "<group>"; }; >+ E92EE00621154AC40042F960 /* TestFamily.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestFamily.m; sourceTree = "<group>"; }; >+ E92EE00821154B5A0042F960 /* TestDescription.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestDescription.h; sourceTree = "<group>"; }; >+ E92EE00921154B5A0042F960 /* TestDescription.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestDescription.m; sourceTree = "<group>"; }; >+ E92EE00B211554980042F960 /* _Shared.whlsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = _Shared.whlsl; sourceTree = "<group>"; }; >+ E92EE00D211563300042F960 /* TestFamilyRunner.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestFamilyRunner.h; sourceTree = "<group>"; }; >+ E92EE00E211563300042F960 /* TestFamilyRunner.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestFamilyRunner.m; sourceTree = "<group>"; }; >+ E94C06C020F56A4000672992 /* WHLSL Tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WHLSL Tests.app"; sourceTree = BUILT_PRODUCTS_DIR; }; >+ E94C06C920F56A4200672992 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; >+ E94C06CE20F56A4200672992 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; >+ E94C06CF20F56A4200672992 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; >+ E94C06D120F56A4200672992 /* WHLSL.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WHLSL.entitlements; sourceTree = "<group>"; }; >+ E94C06D620F56A4200672992 /* WHLSL TestsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "WHLSL TestsTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; >+ E94C06DA20F56A4200672992 /* WHLSL_ToyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WHLSL_ToyTests.m; sourceTree = "<group>"; }; >+ E94C06DC20F56A4200672992 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; >+ E94C06F720F56C6000672992 /* compiler.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = compiler.js; path = ../../compiler.js; sourceTree = "<group>"; }; >+ E94C06F920F56CA300672992 /* DereferenceExpression.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = DereferenceExpression.js; path = ../../../DereferenceExpression.js; sourceTree = "<group>"; }; >+ E94C06FA20F56CA300672992 /* CheckRecursion.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = CheckRecursion.js; path = ../../../CheckRecursion.js; sourceTree = "<group>"; }; >+ E94C06FB20F56CA300672992 /* HighZombieFinder.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = HighZombieFinder.js; path = ../../../HighZombieFinder.js; sourceTree = "<group>"; }; >+ E94C06FC20F56CA300672992 /* Block.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = Block.js; path = ../../../Block.js; sourceTree = "<group>"; }; >+ E94C06FD20F56CA300672992 /* EnumLiteral.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = EnumLiteral.js; path = ../../../EnumLiteral.js; sourceTree = "<group>"; }; >+ E94D124E2114BD7600B0F967 /* Mandelbrot.whlsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Mandelbrot.whlsl; sourceTree = "<group>"; }; >+ E94D127E2114C6FF00B0F967 /* Test.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Test.js; path = ../../../Test.js; sourceTree = "<group>"; }; >+ E95569B020F56CD600F5CF34 /* Break.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Break.js; path = ../../../Break.js; sourceTree = "<group>"; }; >+ E95569B120F56CD600F5CF34 /* BoolLiteral.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = BoolLiteral.js; path = ../../../BoolLiteral.js; sourceTree = "<group>"; }; >+ E95569B220F56CD600F5CF34 /* CheckReturns.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckReturns.js; path = ../../../CheckReturns.js; sourceTree = "<group>"; }; >+ E95569B320F56CD600F5CF34 /* CheckLoops.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckLoops.js; path = ../../../CheckLoops.js; sourceTree = "<group>"; }; >+ E95569B420F56CD600F5CF34 /* ArrayType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ArrayType.js; path = ../../../ArrayType.js; sourceTree = "<group>"; }; >+ E95569B520F56CD600F5CF34 /* ArrayRefType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ArrayRefType.js; path = ../../../ArrayRefType.js; sourceTree = "<group>"; }; >+ E95569B620F56CD600F5CF34 /* CheckLiteralTypes.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckLiteralTypes.js; path = ../../../CheckLiteralTypes.js; sourceTree = "<group>"; }; >+ E95569B720F56CD600F5CF34 /* CheckUnreachableCode.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckUnreachableCode.js; path = ../../../CheckUnreachableCode.js; sourceTree = "<group>"; }; >+ E95569B820F56CD600F5CF34 /* Check.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Check.js; path = ../../../Check.js; sourceTree = "<group>"; }; >+ E95569B920F56CD600F5CF34 /* Assignment.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Assignment.js; path = ../../../Assignment.js; sourceTree = "<group>"; }; >+ E95569BA20F56CD600F5CF34 /* AddressSpace.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = AddressSpace.js; path = ../../../AddressSpace.js; sourceTree = "<group>"; }; >+ E95569BB20F56CD600F5CF34 /* CheckRecursiveTypes.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckRecursiveTypes.js; path = ../../../CheckRecursiveTypes.js; sourceTree = "<group>"; }; >+ E95569BC20F56CD700F5CF34 /* All.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = All.js; path = ../../../All.js; sourceTree = "<group>"; }; >+ E95569BD20F56CD700F5CF34 /* AnonymousVariable.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = AnonymousVariable.js; path = ../../../AnonymousVariable.js; sourceTree = "<group>"; }; >+ E95569BE20F56CD700F5CF34 /* AutoWrapper.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = AutoWrapper.js; path = ../../../AutoWrapper.js; sourceTree = "<group>"; }; >+ E95569BF20F56CD700F5CF34 /* CallExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CallExpression.js; path = ../../../CallExpression.js; sourceTree = "<group>"; }; >+ E95569C020F56CD700F5CF34 /* CallFunction.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CallFunction.js; path = ../../../CallFunction.js; sourceTree = "<group>"; }; >+ E95569C120F56CD700F5CF34 /* Checker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Checker.js; path = ../../../Checker.js; sourceTree = "<group>"; }; >+ E95569D420F56CED00F5CF34 /* CheckWrapped.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CheckWrapped.js; path = ../../../CheckWrapped.js; sourceTree = "<group>"; }; >+ E95569D520F56CED00F5CF34 /* ConstexprFolder.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ConstexprFolder.js; path = ../../../ConstexprFolder.js; sourceTree = "<group>"; }; >+ E95569D620F56CED00F5CF34 /* CreateLiteralType.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CreateLiteralType.js; path = ../../../CreateLiteralType.js; sourceTree = "<group>"; }; >+ E95569D720F56CED00F5CF34 /* Continue.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Continue.js; path = ../../../Continue.js; sourceTree = "<group>"; }; >+ E95569D820F56CED00F5CF34 /* CreateLiteral.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CreateLiteral.js; path = ../../../CreateLiteral.js; sourceTree = "<group>"; }; >+ E95569D920F56CED00F5CF34 /* ConvertPtrToArrayRefExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ConvertPtrToArrayRefExpression.js; path = ../../../ConvertPtrToArrayRefExpression.js; sourceTree = "<group>"; }; >+ E95569DA20F56CED00F5CF34 /* ConstexprTypeParameter.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ConstexprTypeParameter.js; path = ../../../ConstexprTypeParameter.js; sourceTree = "<group>"; }; >+ E95569DB20F56CEE00F5CF34 /* CloneProgram.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CloneProgram.js; path = ../../../CloneProgram.js; sourceTree = "<group>"; }; >+ E95569DC20F56CEE00F5CF34 /* CommaExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = CommaExpression.js; path = ../../../CommaExpression.js; sourceTree = "<group>"; }; >+ E95569E620F56D0500F5CF34 /* FunctionLikeBlock.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FunctionLikeBlock.js; path = ../../../FunctionLikeBlock.js; sourceTree = "<group>"; }; >+ E95569E720F56D0500F5CF34 /* EPtr.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = EPtr.js; path = ../../../EPtr.js; sourceTree = "<group>"; }; >+ E95569E820F56D0500F5CF34 /* FuncDef.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FuncDef.js; path = ../../../FuncDef.js; sourceTree = "<group>"; }; >+ E95569E920F56D0500F5CF34 /* FuncParameter.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FuncParameter.js; path = ../../../FuncParameter.js; sourceTree = "<group>"; }; >+ E95569EA20F56D0500F5CF34 /* FloatLiteralType.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FloatLiteralType.js; path = ../../../FloatLiteralType.js; sourceTree = "<group>"; }; >+ E95569EB20F56D0500F5CF34 /* FoldConstexprs.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FoldConstexprs.js; path = ../../../FoldConstexprs.js; sourceTree = "<group>"; }; >+ E9AD074620F56D5A007F2466 /* DoWhileLoop.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = DoWhileLoop.js; path = ../../../DoWhileLoop.js; sourceTree = "<group>"; }; >+ E9AD074820F56D5A007F2466 /* EBuffer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = EBuffer.js; path = ../../../EBuffer.js; sourceTree = "<group>"; }; >+ E9AD074920F56D5A007F2466 /* EArrayRef.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = EArrayRef.js; path = ../../../EArrayRef.js; sourceTree = "<group>"; }; >+ E9AD074A20F56D5B007F2466 /* EBufferBuilder.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = EBufferBuilder.js; path = ../../../EBufferBuilder.js; sourceTree = "<group>"; }; >+ E9AD074B20F56D5B007F2466 /* DotExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = DotExpression.js; path = ../../../DotExpression.js; sourceTree = "<group>"; }; >+ E9AD075320F56D69007F2466 /* EvaluationCommon.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = EvaluationCommon.js; path = ../../../EvaluationCommon.js; sourceTree = "<group>"; }; >+ E9AD075420F56D69007F2466 /* Expression.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = Expression.js; path = ../../../Expression.js; sourceTree = "<group>"; }; >+ E9AD075520F56D69007F2466 /* EnumMember.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = EnumMember.js; path = ../../../EnumMember.js; sourceTree = "<group>"; }; >+ E9AD075620F56D69007F2466 /* FlattenedStructOffsetGatherer.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FlattenedStructOffsetGatherer.js; path = ../../../FlattenedStructOffsetGatherer.js; sourceTree = "<group>"; }; >+ E9AD075720F56D69007F2466 /* Evaluator.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = Evaluator.js; path = ../../../Evaluator.js; sourceTree = "<group>"; }; >+ E9AD075820F56D69007F2466 /* FindHighZombies.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FindHighZombies.js; path = ../../../FindHighZombies.js; sourceTree = "<group>"; }; >+ E9AD075920F56D69007F2466 /* ExpressionFinder.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ExpressionFinder.js; path = ../../../ExpressionFinder.js; sourceTree = "<group>"; }; >+ E9AD075A20F56D69007F2466 /* EnumType.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = EnumType.js; path = ../../../EnumType.js; sourceTree = "<group>"; }; >+ E9AD075B20F56D69007F2466 /* ExternalOrigin.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = ExternalOrigin.js; path = ../../../ExternalOrigin.js; sourceTree = "<group>"; }; >+ E9AD075C20F56D69007F2466 /* FloatLiteral.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = FloatLiteral.js; path = ../../../FloatLiteral.js; sourceTree = "<group>"; }; >+ E9E11932211E61640014D553 /* Shaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Shaders.metal; sourceTree = "<group>"; }; >+ E9FCEB5520F56D92009B3629 /* Func.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Func.js; path = ../../../Func.js; sourceTree = "<group>"; }; >+ E9FCEB5620F56D92009B3629 /* FuncInstantiator.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = FuncInstantiator.js; path = ../../../FuncInstantiator.js; sourceTree = "<group>"; }; >+ E9FCEB5720F56D93009B3629 /* IfStatement.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = IfStatement.js; path = ../../../IfStatement.js; sourceTree = "<group>"; }; >+ E9FCEB5820F56D93009B3629 /* IdentityExpression.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = IdentityExpression.js; path = ../../../IdentityExpression.js; sourceTree = "<group>"; }; >+ E9FCEB5920F56D93009B3629 /* FlattenProtocolExtends.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = FlattenProtocolExtends.js; path = ../../../FlattenProtocolExtends.js; sourceTree = "<group>"; }; >+ E9FCEB5A20F56D93009B3629 /* ForLoop.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ForLoop.js; path = ../../../ForLoop.js; sourceTree = "<group>"; }; >+ E9FCEB5B20F56D93009B3629 /* Field.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = Field.js; path = ../../../Field.js; sourceTree = "<group>"; }; >+ E9FCEB6320F56DA4009B3629 /* IndexExpression.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = IndexExpression.js; path = ../../../IndexExpression.js; sourceTree = "<group>"; }; >+ E9FCEB6420F56DA5009B3629 /* LateChecker.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = LateChecker.js; path = ../../../LateChecker.js; sourceTree = "<group>"; }; >+ E9FCEB6520F56DA5009B3629 /* InferTypesForCall.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = InferTypesForCall.js; path = ../../../InferTypesForCall.js; sourceTree = "<group>"; }; >+ E9FCEB6620F56DA5009B3629 /* Inline.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; name = Inline.js; path = ../../../Inline.js; sourceTree = "<group>"; }; >+/* End PBXFileReference section */ >+ >+/* Begin PBXFrameworksBuildPhase section */ >+ E94C06BD20F56A4000672992 /* Frameworks */ = { >+ isa = PBXFrameworksBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ E92D109120F56F5700D776B2 /* JavaScriptCore.framework in Frameworks */, >+ E92D108F20F56F4F00D776B2 /* Metal.framework in Frameworks */, >+ E92D108D20F56F4500D776B2 /* MetalKit.framework in Frameworks */, >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+ E94C06D320F56A4200672992 /* Frameworks */ = { >+ isa = PBXFrameworksBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+/* End PBXFrameworksBuildPhase section */ >+ >+/* Begin PBXGroup section */ >+ E906B04A2114BD1D00AD1C5E /* Demo shaders */ = { >+ isa = PBXGroup; >+ children = ( >+ E92D109220F5734900D776B2 /* Default.whlsl */, >+ E906B04521139B7700AD1C5E /* Julia.whlsl */, >+ E94D124E2114BD7600B0F967 /* Mandelbrot.whlsl */, >+ ); >+ path = "Demo shaders"; >+ sourceTree = "<group>"; >+ }; >+ E92D108B20F56F4400D776B2 /* Frameworks */ = { >+ isa = PBXGroup; >+ children = ( >+ E92D109020F56F5700D776B2 /* JavaScriptCore.framework */, >+ E92D108E20F56F4F00D776B2 /* Metal.framework */, >+ E92D108C20F56F4500D776B2 /* MetalKit.framework */, >+ ); >+ name = Frameworks; >+ sourceTree = "<group>"; >+ }; >+ E92D11AE20F70BAE00D776B2 /* Renderer */ = { >+ isa = PBXGroup; >+ children = ( >+ E92D11AB20F7081500D776B2 /* OffscreenRenderer.h */, >+ E92D11AC20F7081500D776B2 /* OffscreenRenderer.m */, >+ E92D10AD20F57C9F00D776B2 /* OnscreenRenderer.h */, >+ E92D10AE20F57C9F00D776B2 /* OnscreenRenderer.m */, >+ E92D111320F6FFB600D776B2 /* Renderer.h */, >+ E92D111420F6FFB600D776B2 /* Renderer.m */, >+ ); >+ path = Renderer; >+ sourceTree = "<group>"; >+ }; >+ E92EDFF4211546910042F960 /* App */ = { >+ isa = PBXGroup; >+ children = ( >+ E92EDFF5211546A40042F960 /* AppDelegate.h */, >+ E92EDFF7211546A40042F960 /* AppDelegate.m */, >+ E92EDFF8211546A40042F960 /* CustomMetalView.h */, >+ E92EDFF6211546A40042F960 /* CustomMetalView.m */, >+ E92EDFFE211546AB0042F960 /* Main.storyboard */, >+ E92EDFF9211546A40042F960 /* ViewController.h */, >+ E92EDFFA211546A40042F960 /* ViewController.m */, >+ ); >+ name = App; >+ sourceTree = "<group>"; >+ }; >+ E92EE0012115499E0042F960 /* Test execution */ = { >+ isa = PBXGroup; >+ children = ( >+ E92EE00B211554980042F960 /* _Shared.whlsl */, >+ E92EE002211549C50042F960 /* TestCallArgument.h */, >+ E92EE003211549C50042F960 /* TestCallArgument.m */, >+ E92EE00821154B5A0042F960 /* TestDescription.h */, >+ E92EE00921154B5A0042F960 /* TestDescription.m */, >+ E92EE00521154AC40042F960 /* TestFamily.h */, >+ E92EE00621154AC40042F960 /* TestFamily.m */, >+ E92EE00D211563300042F960 /* TestFamilyRunner.h */, >+ E92EE00E211563300042F960 /* TestFamilyRunner.m */, >+ ); >+ name = "Test execution"; >+ sourceTree = "<group>"; >+ }; >+ E94C06B720F56A4000672992 = { >+ isa = PBXGroup; >+ children = ( >+ E94C06C220F56A4000672992 /* Core */, >+ E92D108B20F56F4400D776B2 /* Frameworks */, >+ E94C06C120F56A4000672992 /* Products */, >+ E94C06D920F56A4200672992 /* WHLSL Tests */, >+ ); >+ sourceTree = "<group>"; >+ }; >+ E94C06C120F56A4000672992 /* Products */ = { >+ isa = PBXGroup; >+ children = ( >+ E94C06C020F56A4000672992 /* WHLSL Tests.app */, >+ E94C06D620F56A4200672992 /* WHLSL TestsTests.xctest */, >+ ); >+ name = Products; >+ sourceTree = "<group>"; >+ }; >+ E94C06C220F56A4000672992 /* Core */ = { >+ isa = PBXGroup; >+ children = ( >+ E92EDFF4211546910042F960 /* App */, >+ E906B04A2114BD1D00AD1C5E /* Demo shaders */, >+ E9E11931211E614D0014D553 /* Metal equivalents */, >+ E92D11AE20F70BAE00D776B2 /* Renderer */, >+ E94C06F620F56C4F00672992 /* Scripts */, >+ E92EE0012115499E0042F960 /* Test execution */, >+ E94C06C920F56A4200672992 /* Assets.xcassets */, >+ E92D108820F56F0600D776B2 /* Compiler.h */, >+ E92D108920F56F0600D776B2 /* Compiler.m */, >+ E92D11B920F7F67300D776B2 /* CompileResult.h */, >+ E92D11BA20F7F67300D776B2 /* CompileResult.m */, >+ E94C06CE20F56A4200672992 /* Info.plist */, >+ E94C06CF20F56A4200672992 /* main.m */, >+ E94C06D120F56A4200672992 /* WHLSL.entitlements */, >+ ); >+ path = Core; >+ sourceTree = "<group>"; >+ }; >+ E94C06D920F56A4200672992 /* WHLSL Tests */ = { >+ isa = PBXGroup; >+ children = ( >+ E94C06DC20F56A4200672992 /* Info.plist */, >+ E94C06DA20F56A4200672992 /* WHLSL_ToyTests.m */, >+ ); >+ name = "WHLSL Tests"; >+ path = "WHLSL ToyTests"; >+ sourceTree = "<group>"; >+ }; >+ E94C06F620F56C4F00672992 /* Scripts */ = { >+ isa = PBXGroup; >+ children = ( >+ E95569BA20F56CD600F5CF34 /* AddressSpace.js */, >+ E95569BC20F56CD700F5CF34 /* All.js */, >+ E95569BD20F56CD700F5CF34 /* AnonymousVariable.js */, >+ E95569B520F56CD600F5CF34 /* ArrayRefType.js */, >+ E95569B420F56CD600F5CF34 /* ArrayType.js */, >+ E95569B920F56CD600F5CF34 /* Assignment.js */, >+ E95569BE20F56CD700F5CF34 /* AutoWrapper.js */, >+ E94C06FC20F56CA300672992 /* Block.js */, >+ E95569B120F56CD600F5CF34 /* BoolLiteral.js */, >+ E95569B020F56CD600F5CF34 /* Break.js */, >+ E95569BF20F56CD700F5CF34 /* CallExpression.js */, >+ E95569C020F56CD700F5CF34 /* CallFunction.js */, >+ E95569B820F56CD600F5CF34 /* Check.js */, >+ E95569C120F56CD700F5CF34 /* Checker.js */, >+ E95569B620F56CD600F5CF34 /* CheckLiteralTypes.js */, >+ E95569B320F56CD600F5CF34 /* CheckLoops.js */, >+ E94C06FA20F56CA300672992 /* CheckRecursion.js */, >+ E95569BB20F56CD600F5CF34 /* CheckRecursiveTypes.js */, >+ E95569B220F56CD600F5CF34 /* CheckReturns.js */, >+ E95569B720F56CD600F5CF34 /* CheckUnreachableCode.js */, >+ E95569D420F56CED00F5CF34 /* CheckWrapped.js */, >+ E95569DB20F56CEE00F5CF34 /* CloneProgram.js */, >+ E95569DC20F56CEE00F5CF34 /* CommaExpression.js */, >+ E94C06F720F56C6000672992 /* compiler.js */, >+ E95569D520F56CED00F5CF34 /* ConstexprFolder.js */, >+ E95569DA20F56CED00F5CF34 /* ConstexprTypeParameter.js */, >+ E95569D720F56CED00F5CF34 /* Continue.js */, >+ E95569D920F56CED00F5CF34 /* ConvertPtrToArrayRefExpression.js */, >+ E95569D820F56CED00F5CF34 /* CreateLiteral.js */, >+ E95569D620F56CED00F5CF34 /* CreateLiteralType.js */, >+ E94C06F920F56CA300672992 /* DereferenceExpression.js */, >+ E9AD074B20F56D5B007F2466 /* DotExpression.js */, >+ E9AD074620F56D5A007F2466 /* DoWhileLoop.js */, >+ E9AD074920F56D5A007F2466 /* EArrayRef.js */, >+ E9AD074820F56D5A007F2466 /* EBuffer.js */, >+ E9AD074A20F56D5B007F2466 /* EBufferBuilder.js */, >+ E94C06FD20F56CA300672992 /* EnumLiteral.js */, >+ E9AD075520F56D69007F2466 /* EnumMember.js */, >+ E9AD075A20F56D69007F2466 /* EnumType.js */, >+ E95569E720F56D0500F5CF34 /* EPtr.js */, >+ E9AD075320F56D69007F2466 /* EvaluationCommon.js */, >+ E9AD075720F56D69007F2466 /* Evaluator.js */, >+ E9AD075420F56D69007F2466 /* Expression.js */, >+ E9AD075920F56D69007F2466 /* ExpressionFinder.js */, >+ E9AD075B20F56D69007F2466 /* ExternalOrigin.js */, >+ E9FCEB5B20F56D93009B3629 /* Field.js */, >+ E9AD075820F56D69007F2466 /* FindHighZombies.js */, >+ E9AD075620F56D69007F2466 /* FlattenedStructOffsetGatherer.js */, >+ E9FCEB5920F56D93009B3629 /* FlattenProtocolExtends.js */, >+ E9AD075C20F56D69007F2466 /* FloatLiteral.js */, >+ E95569EA20F56D0500F5CF34 /* FloatLiteralType.js */, >+ E95569EB20F56D0500F5CF34 /* FoldConstexprs.js */, >+ E9FCEB5A20F56D93009B3629 /* ForLoop.js */, >+ E9FCEB5520F56D92009B3629 /* Func.js */, >+ E95569E820F56D0500F5CF34 /* FuncDef.js */, >+ E9FCEB5620F56D92009B3629 /* FuncInstantiator.js */, >+ E95569E920F56D0500F5CF34 /* FuncParameter.js */, >+ E95569E620F56D0500F5CF34 /* FunctionLikeBlock.js */, >+ E94C06FB20F56CA300672992 /* HighZombieFinder.js */, >+ E9FCEB5820F56D93009B3629 /* IdentityExpression.js */, >+ E9FCEB5720F56D93009B3629 /* IfStatement.js */, >+ E9FCEB6320F56DA4009B3629 /* IndexExpression.js */, >+ E9FCEB6520F56DA5009B3629 /* InferTypesForCall.js */, >+ E9FCEB6620F56DA5009B3629 /* Inline.js */, >+ E92D0FE820F56DDD00D776B2 /* Inliner.js */, >+ E92D0FE620F56DDD00D776B2 /* InstantiateImmediates.js */, >+ E92D0FE420F56DDD00D776B2 /* IntLiteral.js */, >+ E92D0FE520F56DDD00D776B2 /* IntLiteralType.js */, >+ E92D0FE720F56DDD00D776B2 /* Intrinsics.js */, >+ E9FCEB6420F56DA5009B3629 /* LateChecker.js */, >+ E92D0FF120F56DEC00D776B2 /* Lexer.js */, >+ E92D0FF020F56DEB00D776B2 /* LexerToken.js */, >+ E92D0FF220F56DEC00D776B2 /* LiteralTypeChecker.js */, >+ E92D0FEE20F56DEB00D776B2 /* LogicalExpression.js */, >+ E92D0FEF20F56DEB00D776B2 /* LogicalNot.js */, >+ E92D0FFB20F56DFB00D776B2 /* LoopChecker.js */, >+ E92D0FFC20F56DFB00D776B2 /* MakeArrayRefExpression.js */, >+ E92D0FF920F56DFA00D776B2 /* MakePtrExpression.js */, >+ E92D0FF820F56DFA00D776B2 /* NameContext.js */, >+ E92D0FFA20F56DFB00D776B2 /* NameFinder.js */, >+ E92D100320F56E0900D776B2 /* NameResolver.js */, >+ E92D100520F56E0900D776B2 /* NativeFunc.js */, >+ E92D100420F56E0900D776B2 /* NativeFuncInstance.js */, >+ E92D100620F56E0900D776B2 /* NativeType.js */, >+ E92D100220F56E0800D776B2 /* NativeTypeInstance.js */, >+ E92D100F20F56E1500D776B2 /* Node.js */, >+ E92D100D20F56E1500D776B2 /* NormalUsePropertyResolver.js */, >+ E92D100C20F56E1500D776B2 /* NullLiteral.js */, >+ E92D101020F56E1500D776B2 /* NullType.js */, >+ E92D100E20F56E1500D776B2 /* OriginKind.js */, >+ E92D101920F56E2200D776B2 /* OverloadResolutionFailure.js */, >+ E92D101720F56E2200D776B2 /* Parse.js */, >+ E92D101820F56E2200D776B2 /* Prepare.js */, >+ E92D101A20F56E2200D776B2 /* Program.js */, >+ E92D101620F56E2100D776B2 /* ProgramWithUnnecessaryThingsRemoved.js */, >+ E92D102320F56E2F00D776B2 /* PropertyAccessExpression.js */, >+ E92D102020F56E2F00D776B2 /* PropertyResolver.js */, >+ E92D102120F56E2F00D776B2 /* Protocol.js */, >+ E92D102420F56E3000D776B2 /* ProtocolDecl.js */, >+ E92D102220F56E2F00D776B2 /* ProtocolFuncDecl.js */, >+ E92D102D20F56E4000D776B2 /* ProtocolRef.js */, >+ E92D102B20F56E3F00D776B2 /* PtrType.js */, >+ E92D102A20F56E3F00D776B2 /* ReadModifyWriteExpression.js */, >+ E92D102C20F56E3F00D776B2 /* RecursionChecker.js */, >+ E92D102E20F56E4000D776B2 /* RecursiveTypeChecker.js */, >+ E92D103520F56E4F00D776B2 /* ReferenceType.js */, >+ E92D103420F56E4F00D776B2 /* ResolveNames.js */, >+ E92D103820F56E4F00D776B2 /* ResolveOverloadImpl.js */, >+ E92D103620F56E4F00D776B2 /* ResolveProperties.js */, >+ E92D103720F56E4F00D776B2 /* ResolveTypeDefs.js */, >+ E92D103E20F56E6100D776B2 /* Return.js */, >+ E92D104020F56E6200D776B2 /* ReturnChecker.js */, >+ E92D104220F56E6200D776B2 /* ReturnException.js */, >+ E92D104120F56E6200D776B2 /* Rewriter.js */, >+ E92D103F20F56E6200D776B2 /* StandardLibrary.js */, >+ E92D104820F56E7300D776B2 /* StatementCloner.js */, >+ E92D104920F56E7300D776B2 /* StructLayoutBuilder.js */, >+ E92D104A20F56E7300D776B2 /* StructType.js */, >+ E92D104C20F56E7300D776B2 /* Substitution.js */, >+ E92D104B20F56E7300D776B2 /* SwitchCase.js */, >+ E92D105220F56E8400D776B2 /* SwitchStatement.js */, >+ E9292D8D21127873006130E3 /* SwizzleOp.js */, >+ E92D105420F56E8500D776B2 /* SynthesizeEnumFunctions.js */, >+ E92D105320F56E8400D776B2 /* SynthesizeStructAccessors.js */, >+ E94D127E2114C6FF00B0F967 /* Test.js */, >+ E92D105620F56E8500D776B2 /* TrapStatement.js */, >+ E92D105520F56E8500D776B2 /* Type.js */, >+ E92D105F20F56E9500D776B2 /* TypeDef.js */, >+ E92D105E20F56E9500D776B2 /* TypeDefResolver.js */, >+ E92D106020F56E9500D776B2 /* TypedValue.js */, >+ E92D105D20F56E9500D776B2 /* TypeOrVariableRef.js */, >+ E92D105C20F56E9400D776B2 /* TypeParameterRewriter.js */, >+ E92D106620F56EA400D776B2 /* TypeRef.js */, >+ E92D106A20F56EA500D776B2 /* TypeVariable.js */, >+ E92D106920F56EA500D776B2 /* TypeVariableTracker.js */, >+ E92D106820F56EA400D776B2 /* UintLiteral.js */, >+ E92D106720F56EA400D776B2 /* UintLiteralType.js */, >+ E92D107220F56EBB00D776B2 /* UnificationContext.js */, >+ E92D107320F56EBC00D776B2 /* UnreachableCodeChecker.js */, >+ E92D107420F56EBC00D776B2 /* Value.js */, >+ E92D107020F56EBB00D776B2 /* VariableDecl.js */, >+ E92D107120F56EBB00D776B2 /* VariableRef.js */, >+ E92D107C20F56ECF00D776B2 /* VisitingSet.js */, >+ E92D107A20F56ECF00D776B2 /* Visitor.js */, >+ E92D107D20F56ECF00D776B2 /* WhileLoop.js */, >+ E92D107B20F56ECF00D776B2 /* WrapChecker.js */, >+ E92D108220F56EDE00D776B2 /* WSyntaxError.js */, >+ E92D108420F56EDE00D776B2 /* WTrapError.js */, >+ E92D108320F56EDE00D776B2 /* WTypeError.js */, >+ ); >+ name = Scripts; >+ sourceTree = "<group>"; >+ }; >+ E9E11931211E614D0014D553 /* Metal equivalents */ = { >+ isa = PBXGroup; >+ children = ( >+ E9E11932211E61640014D553 /* Shaders.metal */, >+ ); >+ path = "Metal equivalents"; >+ sourceTree = "<group>"; >+ }; >+/* End PBXGroup section */ >+ >+/* Begin PBXNativeTarget section */ >+ E94C06BF20F56A4000672992 /* WHLSL Tests */ = { >+ isa = PBXNativeTarget; >+ buildConfigurationList = E94C06EA20F56A4200672992 /* Build configuration list for PBXNativeTarget "WHLSL Tests" */; >+ buildPhases = ( >+ E925653C21234AA1001A89D9 /* ShellScript */, >+ E94C06BC20F56A4000672992 /* Sources */, >+ E94C06BD20F56A4000672992 /* Frameworks */, >+ E94C06BE20F56A4000672992 /* Resources */, >+ ); >+ buildRules = ( >+ ); >+ dependencies = ( >+ ); >+ name = "WHLSL Tests"; >+ productName = "WHLSL Toy"; >+ productReference = E94C06C020F56A4000672992 /* WHLSL Tests.app */; >+ productType = "com.apple.product-type.application"; >+ }; >+ E94C06D520F56A4200672992 /* WHLSL TestsTests */ = { >+ isa = PBXNativeTarget; >+ buildConfigurationList = E94C06ED20F56A4200672992 /* Build configuration list for PBXNativeTarget "WHLSL TestsTests" */; >+ buildPhases = ( >+ E94C06D220F56A4200672992 /* Sources */, >+ E94C06D320F56A4200672992 /* Frameworks */, >+ E94C06D420F56A4200672992 /* Resources */, >+ ); >+ buildRules = ( >+ ); >+ dependencies = ( >+ E94C06D820F56A4200672992 /* PBXTargetDependency */, >+ ); >+ name = "WHLSL TestsTests"; >+ productName = "WHLSL ToyTests"; >+ productReference = E94C06D620F56A4200672992 /* WHLSL TestsTests.xctest */; >+ productType = "com.apple.product-type.bundle.unit-test"; >+ }; >+/* End PBXNativeTarget section */ >+ >+/* Begin PBXProject section */ >+ E94C06B820F56A4000672992 /* Project object */ = { >+ isa = PBXProject; >+ attributes = { >+ LastUpgradeCheck = 1000; >+ ORGANIZATIONNAME = "Apple, Inc."; >+ TargetAttributes = { >+ E94C06BF20F56A4000672992 = { >+ CreatedOnToolsVersion = 10.0; >+ }; >+ E94C06D520F56A4200672992 = { >+ CreatedOnToolsVersion = 10.0; >+ TestTargetID = E94C06BF20F56A4000672992; >+ }; >+ }; >+ }; >+ buildConfigurationList = E94C06BB20F56A4000672992 /* Build configuration list for PBXProject "WHLSL Tests" */; >+ compatibilityVersion = "Xcode 9.3"; >+ developmentRegion = en; >+ hasScannedForEncodings = 0; >+ knownRegions = ( >+ en, >+ Base, >+ ); >+ mainGroup = E94C06B720F56A4000672992; >+ productRefGroup = E94C06C120F56A4000672992 /* Products */; >+ projectDirPath = ""; >+ projectRoot = ""; >+ targets = ( >+ E94C06BF20F56A4000672992 /* WHLSL Tests */, >+ E94C06D520F56A4200672992 /* WHLSL TestsTests */, >+ ); >+ }; >+/* End PBXProject section */ >+ >+/* Begin PBXResourcesBuildPhase section */ >+ E94C06BE20F56A4000672992 /* Resources */ = { >+ isa = PBXResourcesBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ E92EE00C211554980042F960 /* _Shared.whlsl in Resources */, >+ E92D111620F7060E00D776B2 /* AddressSpace.js in Resources */, >+ E92D111720F7060E00D776B2 /* All.js in Resources */, >+ E92D111820F7060E00D776B2 /* AnonymousVariable.js in Resources */, >+ E92D111920F7060E00D776B2 /* ArrayRefType.js in Resources */, >+ E92D111A20F7060E00D776B2 /* ArrayType.js in Resources */, >+ E94C06CA20F56A4200672992 /* Assets.xcassets in Resources */, >+ E92D111B20F7060E00D776B2 /* Assignment.js in Resources */, >+ E92D111C20F7060E00D776B2 /* AutoWrapper.js in Resources */, >+ E92D111D20F7060E00D776B2 /* Block.js in Resources */, >+ E92D111E20F7060E00D776B2 /* BoolLiteral.js in Resources */, >+ E92D111F20F7060E00D776B2 /* Break.js in Resources */, >+ E92D112020F7060E00D776B2 /* CallExpression.js in Resources */, >+ E92D112120F7060E00D776B2 /* CallFunction.js in Resources */, >+ E92D112220F7060E00D776B2 /* Check.js in Resources */, >+ E92D112320F7060E00D776B2 /* Checker.js in Resources */, >+ E92D112420F7060E00D776B2 /* CheckLiteralTypes.js in Resources */, >+ E92D112520F7060E00D776B2 /* CheckLoops.js in Resources */, >+ E92D112620F7060E00D776B2 /* CheckRecursion.js in Resources */, >+ E92D112720F7060E00D776B2 /* CheckRecursiveTypes.js in Resources */, >+ E92D112820F7060E00D776B2 /* CheckReturns.js in Resources */, >+ E92D112920F7060E00D776B2 /* CheckUnreachableCode.js in Resources */, >+ E92D112A20F7060E00D776B2 /* CheckWrapped.js in Resources */, >+ E92D112B20F7060E00D776B2 /* CloneProgram.js in Resources */, >+ E92D112C20F7060E00D776B2 /* CommaExpression.js in Resources */, >+ E92D112D20F7060E00D776B2 /* compiler.js in Resources */, >+ E92D112E20F7060E00D776B2 /* ConstexprFolder.js in Resources */, >+ E92D112F20F7060E00D776B2 /* ConstexprTypeParameter.js in Resources */, >+ E92D113020F7060E00D776B2 /* Continue.js in Resources */, >+ E92D113120F7060E00D776B2 /* ConvertPtrToArrayRefExpression.js in Resources */, >+ E92D113220F7060E00D776B2 /* CreateLiteral.js in Resources */, >+ E92D113320F7060E00D776B2 /* CreateLiteralType.js in Resources */, >+ E92D109320F5734900D776B2 /* Default.whlsl in Resources */, >+ E92D113420F7060E00D776B2 /* DereferenceExpression.js in Resources */, >+ E92D113520F7060E00D776B2 /* DotExpression.js in Resources */, >+ E92D113820F7060E00D776B2 /* DoWhileLoop.js in Resources */, >+ E92D113920F7060E00D776B2 /* EArrayRef.js in Resources */, >+ E92D113A20F7060E00D776B2 /* EBuffer.js in Resources */, >+ E92D113B20F7060E00D776B2 /* EBufferBuilder.js in Resources */, >+ E92D113C20F7060E00D776B2 /* EnumLiteral.js in Resources */, >+ E92D113D20F7060E00D776B2 /* EnumMember.js in Resources */, >+ E92D113E20F7060E00D776B2 /* EnumType.js in Resources */, >+ E92D113F20F7060E00D776B2 /* EPtr.js in Resources */, >+ E92D114020F7060E00D776B2 /* EvaluationCommon.js in Resources */, >+ E92D114120F7060E00D776B2 /* Evaluator.js in Resources */, >+ E92D114220F7060E00D776B2 /* Expression.js in Resources */, >+ E92D114320F7060E00D776B2 /* ExpressionFinder.js in Resources */, >+ E92D114420F7060E00D776B2 /* ExternalOrigin.js in Resources */, >+ E92D114520F7060E00D776B2 /* Field.js in Resources */, >+ E92D114620F7060E00D776B2 /* FindHighZombies.js in Resources */, >+ E92D114720F7060E00D776B2 /* FlattenedStructOffsetGatherer.js in Resources */, >+ E92D114820F7060E00D776B2 /* FlattenProtocolExtends.js in Resources */, >+ E92D114920F7060E00D776B2 /* FloatLiteral.js in Resources */, >+ E92D114A20F7060E00D776B2 /* FloatLiteralType.js in Resources */, >+ E92D114B20F7060E00D776B2 /* FoldConstexprs.js in Resources */, >+ E92D114C20F7060E00D776B2 /* ForLoop.js in Resources */, >+ E92D114D20F7060E00D776B2 /* Func.js in Resources */, >+ E92D114E20F7060E00D776B2 /* FuncDef.js in Resources */, >+ E92D114F20F7060E00D776B2 /* FuncInstantiator.js in Resources */, >+ E92D115020F7060E00D776B2 /* FuncParameter.js in Resources */, >+ E92D115120F7060E00D776B2 /* FunctionLikeBlock.js in Resources */, >+ E92D115220F7060E00D776B2 /* HighZombieFinder.js in Resources */, >+ E92D115320F7060E00D776B2 /* IdentityExpression.js in Resources */, >+ E92D115420F7060E00D776B2 /* IfStatement.js in Resources */, >+ E92D115520F7060E00D776B2 /* IndexExpression.js in Resources */, >+ E92D115620F7060E00D776B2 /* InferTypesForCall.js in Resources */, >+ E92D115720F7060E00D776B2 /* Inline.js in Resources */, >+ E92D115820F7060E00D776B2 /* Inliner.js in Resources */, >+ E92D115920F7060E00D776B2 /* InstantiateImmediates.js in Resources */, >+ E92D115A20F7060E00D776B2 /* IntLiteral.js in Resources */, >+ E92D115B20F7060E00D776B2 /* IntLiteralType.js in Resources */, >+ E92D115C20F7060E00D776B2 /* Intrinsics.js in Resources */, >+ E906B04621139B7700AD1C5E /* Julia.whlsl in Resources */, >+ E92D115D20F7060E00D776B2 /* LateChecker.js in Resources */, >+ E92D115E20F7060E00D776B2 /* Lexer.js in Resources */, >+ E92D115F20F7060E00D776B2 /* LexerToken.js in Resources */, >+ E92D116020F7060E00D776B2 /* LiteralTypeChecker.js in Resources */, >+ E92D116120F7060E00D776B2 /* LogicalExpression.js in Resources */, >+ E92D116220F7060E00D776B2 /* LogicalNot.js in Resources */, >+ E92D116320F7060E00D776B2 /* LoopChecker.js in Resources */, >+ E92EE000211546AB0042F960 /* Main.storyboard in Resources */, >+ E92D116420F7060E00D776B2 /* MakeArrayRefExpression.js in Resources */, >+ E92D116520F7060E00D776B2 /* MakePtrExpression.js in Resources */, >+ E94D124F2114BD7600B0F967 /* Mandelbrot.whlsl in Resources */, >+ E92D116620F7060E00D776B2 /* NameContext.js in Resources */, >+ E92D116720F7060E00D776B2 /* NameFinder.js in Resources */, >+ E92D116820F7060E00D776B2 /* NameResolver.js in Resources */, >+ E92D116920F7060E00D776B2 /* NativeFunc.js in Resources */, >+ E92D116A20F7060E00D776B2 /* NativeFuncInstance.js in Resources */, >+ E92D116B20F7060E00D776B2 /* NativeType.js in Resources */, >+ E92D116C20F7060E00D776B2 /* NativeTypeInstance.js in Resources */, >+ E92D116D20F7060E00D776B2 /* Node.js in Resources */, >+ E92D116E20F7060E00D776B2 /* NormalUsePropertyResolver.js in Resources */, >+ E92D116F20F7060E00D776B2 /* NullLiteral.js in Resources */, >+ E92D117020F7060E00D776B2 /* NullType.js in Resources */, >+ E92D117120F7060E00D776B2 /* OriginKind.js in Resources */, >+ E92D117220F7060E00D776B2 /* OverloadResolutionFailure.js in Resources */, >+ E92D117320F7060E00D776B2 /* Parse.js in Resources */, >+ E92D117420F7060E00D776B2 /* Prepare.js in Resources */, >+ E92D117520F7060E00D776B2 /* Program.js in Resources */, >+ E92D117620F7060E00D776B2 /* ProgramWithUnnecessaryThingsRemoved.js in Resources */, >+ E92D117720F7060E00D776B2 /* PropertyAccessExpression.js in Resources */, >+ E92D117820F7060E00D776B2 /* PropertyResolver.js in Resources */, >+ E92D117920F7060E00D776B2 /* Protocol.js in Resources */, >+ E92D117A20F7060E00D776B2 /* ProtocolDecl.js in Resources */, >+ E92D117B20F7060E00D776B2 /* ProtocolFuncDecl.js in Resources */, >+ E92D117C20F7060E00D776B2 /* ProtocolRef.js in Resources */, >+ E92D117D20F7060E00D776B2 /* PtrType.js in Resources */, >+ E92D117E20F7060E00D776B2 /* ReadModifyWriteExpression.js in Resources */, >+ E92D117F20F7060E00D776B2 /* RecursionChecker.js in Resources */, >+ E92D118020F7060E00D776B2 /* RecursiveTypeChecker.js in Resources */, >+ E92D118120F7060E00D776B2 /* ReferenceType.js in Resources */, >+ E92D118220F7060E00D776B2 /* ResolveNames.js in Resources */, >+ E92D118320F7060E00D776B2 /* ResolveOverloadImpl.js in Resources */, >+ E92D118420F7060E00D776B2 /* ResolveProperties.js in Resources */, >+ E92D118520F7060E00D776B2 /* ResolveTypeDefs.js in Resources */, >+ E92D118620F7060E00D776B2 /* Return.js in Resources */, >+ E92D118720F7060E00D776B2 /* ReturnChecker.js in Resources */, >+ E92D118820F7060E00D776B2 /* ReturnException.js in Resources */, >+ E92D118920F7060E00D776B2 /* Rewriter.js in Resources */, >+ E92D118A20F7060E00D776B2 /* StandardLibrary.js in Resources */, >+ E92D118B20F7060E00D776B2 /* StatementCloner.js in Resources */, >+ E92D118C20F7060E00D776B2 /* StructLayoutBuilder.js in Resources */, >+ E92D118D20F7060E00D776B2 /* StructType.js in Resources */, >+ E92D118E20F7060E00D776B2 /* Substitution.js in Resources */, >+ E92D118F20F7060E00D776B2 /* SwitchCase.js in Resources */, >+ E92D119020F7060E00D776B2 /* SwitchStatement.js in Resources */, >+ E9292D8E21127873006130E3 /* SwizzleOp.js in Resources */, >+ E92D119120F7060E00D776B2 /* SynthesizeEnumFunctions.js in Resources */, >+ E92D119220F7060E00D776B2 /* SynthesizeStructAccessors.js in Resources */, >+ E94D127F2114C6FF00B0F967 /* Test.js in Resources */, >+ E92D119320F7060E00D776B2 /* TrapStatement.js in Resources */, >+ E92D119420F7060E00D776B2 /* Type.js in Resources */, >+ E92D119520F7060E00D776B2 /* TypeDef.js in Resources */, >+ E92D119620F7060E00D776B2 /* TypeDefResolver.js in Resources */, >+ E92D119720F7060E00D776B2 /* TypedValue.js in Resources */, >+ E92D119820F7060E00D776B2 /* TypeOrVariableRef.js in Resources */, >+ E92D119920F7060E00D776B2 /* TypeParameterRewriter.js in Resources */, >+ E92D119A20F7060E00D776B2 /* TypeRef.js in Resources */, >+ E92D119B20F7060E00D776B2 /* TypeVariable.js in Resources */, >+ E92D119C20F7060E00D776B2 /* TypeVariableTracker.js in Resources */, >+ E92D119D20F7060E00D776B2 /* UintLiteral.js in Resources */, >+ E92D119E20F7060E00D776B2 /* UintLiteralType.js in Resources */, >+ E92D119F20F7060E00D776B2 /* UnificationContext.js in Resources */, >+ E92D11A020F7060E00D776B2 /* UnreachableCodeChecker.js in Resources */, >+ E92D11A120F7060E00D776B2 /* Value.js in Resources */, >+ E92D11A220F7060E00D776B2 /* VariableDecl.js in Resources */, >+ E92D11A320F7060E00D776B2 /* VariableRef.js in Resources */, >+ E92D11A420F7060E00D776B2 /* VisitingSet.js in Resources */, >+ E92D11A520F7060E00D776B2 /* Visitor.js in Resources */, >+ E92D11A620F7060E00D776B2 /* WhileLoop.js in Resources */, >+ E92D11A720F7060E00D776B2 /* WrapChecker.js in Resources */, >+ E92D11A820F7060E00D776B2 /* WSyntaxError.js in Resources */, >+ E92D11A920F7060E00D776B2 /* WTrapError.js in Resources */, >+ E92D11AA20F7060E00D776B2 /* WTypeError.js in Resources */, >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+ E94C06D420F56A4200672992 /* Resources */ = { >+ isa = PBXResourcesBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+/* End PBXResourcesBuildPhase section */ >+ >+/* Begin PBXShellScriptBuildPhase section */ >+ E925653C21234AA1001A89D9 /* ShellScript */ = { >+ isa = PBXShellScriptBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ ); >+ inputFileListPaths = ( >+ ); >+ inputPaths = ( >+ ); >+ outputFileListPaths = ( >+ ); >+ outputPaths = ( >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ shellPath = /bin/sh; >+ shellScript = "# Type a script or drag a script file from your workspace to insert its path.\ncd \"$SRCROOT/..\"\ntsc\n"; >+ }; >+/* End PBXShellScriptBuildPhase section */ >+ >+/* Begin PBXSourcesBuildPhase section */ >+ E94C06BC20F56A4000672992 /* Sources */ = { >+ isa = PBXSourcesBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ E92EDFFC211546A40042F960 /* AppDelegate.m in Sources */, >+ E92D108A20F56F0600D776B2 /* Compiler.m in Sources */, >+ E92D11BB20F7F67300D776B2 /* CompileResult.m in Sources */, >+ E92EDFFB211546A40042F960 /* CustomMetalView.m in Sources */, >+ E94C06D020F56A4200672992 /* main.m in Sources */, >+ E92D11AD20F7081500D776B2 /* OffscreenRenderer.m in Sources */, >+ E92D10AF20F57C9F00D776B2 /* OnscreenRenderer.m in Sources */, >+ E92D111520F6FFB600D776B2 /* Renderer.m in Sources */, >+ E9E11933211E61640014D553 /* Shaders.metal in Sources */, >+ E92EE004211549C50042F960 /* TestCallArgument.m in Sources */, >+ E92EE00A21154B5A0042F960 /* TestDescription.m in Sources */, >+ E92EE00721154AC40042F960 /* TestFamily.m in Sources */, >+ E92EE00F211563300042F960 /* TestFamilyRunner.m in Sources */, >+ E92EDFFD211546A40042F960 /* ViewController.m in Sources */, >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+ E94C06D220F56A4200672992 /* Sources */ = { >+ isa = PBXSourcesBuildPhase; >+ buildActionMask = 2147483647; >+ files = ( >+ E94C06DB20F56A4200672992 /* WHLSL_ToyTests.m in Sources */, >+ ); >+ runOnlyForDeploymentPostprocessing = 0; >+ }; >+/* End PBXSourcesBuildPhase section */ >+ >+/* Begin PBXTargetDependency section */ >+ E94C06D820F56A4200672992 /* PBXTargetDependency */ = { >+ isa = PBXTargetDependency; >+ target = E94C06BF20F56A4000672992 /* WHLSL Tests */; >+ targetProxy = E94C06D720F56A4200672992 /* PBXContainerItemProxy */; >+ }; >+/* End PBXTargetDependency section */ >+ >+/* Begin PBXVariantGroup section */ >+ E92EDFFE211546AB0042F960 /* Main.storyboard */ = { >+ isa = PBXVariantGroup; >+ children = ( >+ E92EDFFF211546AB0042F960 /* Base */, >+ ); >+ name = Main.storyboard; >+ sourceTree = "<group>"; >+ }; >+/* End PBXVariantGroup section */ >+ >+/* Begin XCBuildConfiguration section */ >+ E94C06E820F56A4200672992 /* Debug */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ ALWAYS_SEARCH_USER_PATHS = NO; >+ CLANG_ANALYZER_NONNULL = YES; >+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; >+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; >+ CLANG_CXX_LIBRARY = "libc++"; >+ CLANG_ENABLE_MODULES = YES; >+ CLANG_ENABLE_OBJC_ARC = YES; >+ CLANG_ENABLE_OBJC_WEAK = YES; >+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; >+ CLANG_WARN_BOOL_CONVERSION = YES; >+ CLANG_WARN_COMMA = YES; >+ CLANG_WARN_CONSTANT_CONVERSION = YES; >+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; >+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; >+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; >+ CLANG_WARN_EMPTY_BODY = YES; >+ CLANG_WARN_ENUM_CONVERSION = YES; >+ CLANG_WARN_INFINITE_RECURSION = YES; >+ CLANG_WARN_INT_CONVERSION = YES; >+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; >+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; >+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; >+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; >+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; >+ CLANG_WARN_STRICT_PROTOTYPES = YES; >+ CLANG_WARN_SUSPICIOUS_MOVE = YES; >+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; >+ CLANG_WARN_UNREACHABLE_CODE = YES; >+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; >+ CODE_SIGN_IDENTITY = "Mac Developer"; >+ COPY_PHASE_STRIP = NO; >+ DEBUG_INFORMATION_FORMAT = dwarf; >+ ENABLE_STRICT_OBJC_MSGSEND = YES; >+ ENABLE_TESTABILITY = YES; >+ GCC_C_LANGUAGE_STANDARD = gnu11; >+ GCC_DYNAMIC_NO_PIC = NO; >+ GCC_NO_COMMON_BLOCKS = YES; >+ GCC_OPTIMIZATION_LEVEL = 0; >+ GCC_PREPROCESSOR_DEFINITIONS = ( >+ "DEBUG=1", >+ "$(inherited)", >+ ); >+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; >+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; >+ GCC_WARN_UNDECLARED_SELECTOR = YES; >+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; >+ GCC_WARN_UNUSED_FUNCTION = YES; >+ GCC_WARN_UNUSED_VARIABLE = YES; >+ MACOSX_DEPLOYMENT_TARGET = 10.14; >+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; >+ ONLY_ACTIVE_ARCH = YES; >+ SDKROOT = macosx; >+ }; >+ name = Debug; >+ }; >+ E94C06E920F56A4200672992 /* Release */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ ALWAYS_SEARCH_USER_PATHS = NO; >+ CLANG_ANALYZER_NONNULL = YES; >+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; >+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; >+ CLANG_CXX_LIBRARY = "libc++"; >+ CLANG_ENABLE_MODULES = YES; >+ CLANG_ENABLE_OBJC_ARC = YES; >+ CLANG_ENABLE_OBJC_WEAK = YES; >+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; >+ CLANG_WARN_BOOL_CONVERSION = YES; >+ CLANG_WARN_COMMA = YES; >+ CLANG_WARN_CONSTANT_CONVERSION = YES; >+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; >+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; >+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; >+ CLANG_WARN_EMPTY_BODY = YES; >+ CLANG_WARN_ENUM_CONVERSION = YES; >+ CLANG_WARN_INFINITE_RECURSION = YES; >+ CLANG_WARN_INT_CONVERSION = YES; >+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; >+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; >+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; >+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; >+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; >+ CLANG_WARN_STRICT_PROTOTYPES = YES; >+ CLANG_WARN_SUSPICIOUS_MOVE = YES; >+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; >+ CLANG_WARN_UNREACHABLE_CODE = YES; >+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; >+ CODE_SIGN_IDENTITY = "Mac Developer"; >+ COPY_PHASE_STRIP = NO; >+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; >+ ENABLE_NS_ASSERTIONS = NO; >+ ENABLE_STRICT_OBJC_MSGSEND = YES; >+ GCC_C_LANGUAGE_STANDARD = gnu11; >+ GCC_NO_COMMON_BLOCKS = YES; >+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; >+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; >+ GCC_WARN_UNDECLARED_SELECTOR = YES; >+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; >+ GCC_WARN_UNUSED_FUNCTION = YES; >+ GCC_WARN_UNUSED_VARIABLE = YES; >+ MACOSX_DEPLOYMENT_TARGET = 10.14; >+ MTL_ENABLE_DEBUG_INFO = NO; >+ SDKROOT = macosx; >+ }; >+ name = Release; >+ }; >+ E94C06EB20F56A4200672992 /* Debug */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; >+ CODE_SIGN_ENTITLEMENTS = Core/WHLSL.entitlements; >+ CODE_SIGN_IDENTITY = "-"; >+ CODE_SIGN_STYLE = Automatic; >+ COMBINE_HIDPI_IMAGES = YES; >+ DEVELOPMENT_TEAM = ""; >+ INFOPLIST_FILE = Core/Info.plist; >+ LD_RUNPATH_SEARCH_PATHS = ( >+ "$(inherited)", >+ "@executable_path/../Frameworks", >+ ); >+ PRODUCT_BUNDLE_IDENTIFIER = "com.apple.WHLSL-Toy"; >+ PRODUCT_NAME = "$(TARGET_NAME)"; >+ }; >+ name = Debug; >+ }; >+ E94C06EC20F56A4200672992 /* Release */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; >+ CODE_SIGN_ENTITLEMENTS = Core/WHLSL.entitlements; >+ CODE_SIGN_IDENTITY = "-"; >+ CODE_SIGN_STYLE = Automatic; >+ COMBINE_HIDPI_IMAGES = YES; >+ DEVELOPMENT_TEAM = ""; >+ INFOPLIST_FILE = Core/Info.plist; >+ LD_RUNPATH_SEARCH_PATHS = ( >+ "$(inherited)", >+ "@executable_path/../Frameworks", >+ ); >+ PRODUCT_BUNDLE_IDENTIFIER = "com.apple.WHLSL-Toy"; >+ PRODUCT_NAME = "$(TARGET_NAME)"; >+ }; >+ name = Release; >+ }; >+ E94C06EE20F56A4200672992 /* Debug */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ BUNDLE_LOADER = "$(TEST_HOST)"; >+ CODE_SIGN_IDENTITY = "-"; >+ CODE_SIGN_STYLE = Automatic; >+ COMBINE_HIDPI_IMAGES = YES; >+ DEVELOPMENT_TEAM = ""; >+ INFOPLIST_FILE = "WHLSL ToyTests/Info.plist"; >+ LD_RUNPATH_SEARCH_PATHS = ( >+ "$(inherited)", >+ "@executable_path/../Frameworks", >+ "@loader_path/../Frameworks", >+ ); >+ PRODUCT_BUNDLE_IDENTIFIER = "com.apple.WHLSL-ToyTests"; >+ PRODUCT_NAME = "$(TARGET_NAME)"; >+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WHLSL Tests.app/Contents/MacOS/WHLSL Tests"; >+ }; >+ name = Debug; >+ }; >+ E94C06EF20F56A4200672992 /* Release */ = { >+ isa = XCBuildConfiguration; >+ buildSettings = { >+ BUNDLE_LOADER = "$(TEST_HOST)"; >+ CODE_SIGN_IDENTITY = "-"; >+ CODE_SIGN_STYLE = Automatic; >+ COMBINE_HIDPI_IMAGES = YES; >+ DEVELOPMENT_TEAM = ""; >+ INFOPLIST_FILE = "WHLSL ToyTests/Info.plist"; >+ LD_RUNPATH_SEARCH_PATHS = ( >+ "$(inherited)", >+ "@executable_path/../Frameworks", >+ "@loader_path/../Frameworks", >+ ); >+ PRODUCT_BUNDLE_IDENTIFIER = "com.apple.WHLSL-ToyTests"; >+ PRODUCT_NAME = "$(TARGET_NAME)"; >+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WHLSL Tests.app/Contents/MacOS/WHLSL Tests"; >+ }; >+ name = Release; >+ }; >+/* End XCBuildConfiguration section */ >+ >+/* Begin XCConfigurationList section */ >+ E94C06BB20F56A4000672992 /* Build configuration list for PBXProject "WHLSL Tests" */ = { >+ isa = XCConfigurationList; >+ buildConfigurations = ( >+ E94C06E820F56A4200672992 /* Debug */, >+ E94C06E920F56A4200672992 /* Release */, >+ ); >+ defaultConfigurationIsVisible = 0; >+ defaultConfigurationName = Release; >+ }; >+ E94C06EA20F56A4200672992 /* Build configuration list for PBXNativeTarget "WHLSL Tests" */ = { >+ isa = XCConfigurationList; >+ buildConfigurations = ( >+ E94C06EB20F56A4200672992 /* Debug */, >+ E94C06EC20F56A4200672992 /* Release */, >+ ); >+ defaultConfigurationIsVisible = 0; >+ defaultConfigurationName = Release; >+ }; >+ E94C06ED20F56A4200672992 /* Build configuration list for PBXNativeTarget "WHLSL TestsTests" */ = { >+ isa = XCConfigurationList; >+ buildConfigurations = ( >+ E94C06EE20F56A4200672992 /* Debug */, >+ E94C06EF20F56A4200672992 /* Release */, >+ ); >+ defaultConfigurationIsVisible = 0; >+ defaultConfigurationName = Release; >+ }; >+/* End XCConfigurationList section */ >+ }; >+ rootObject = E94C06B820F56A4000672992 /* Project object */; >+} >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/Info.plist b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/Info.plist >new file mode 100644 >index 0000000000000000000000000000000000000000..6c40a6cd0c4af2f0d93b697fbfb066793681b045 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/Info.plist >@@ -0,0 +1,22 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> >+<plist version="1.0"> >+<dict> >+ <key>CFBundleDevelopmentRegion</key> >+ <string>$(DEVELOPMENT_LANGUAGE)</string> >+ <key>CFBundleExecutable</key> >+ <string>$(EXECUTABLE_NAME)</string> >+ <key>CFBundleIdentifier</key> >+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> >+ <key>CFBundleInfoDictionaryVersion</key> >+ <string>6.0</string> >+ <key>CFBundleName</key> >+ <string>$(PRODUCT_NAME)</string> >+ <key>CFBundlePackageType</key> >+ <string>BNDL</string> >+ <key>CFBundleShortVersionString</key> >+ <string>1.0</string> >+ <key>CFBundleVersion</key> >+ <string>1</string> >+</dict> >+</plist> >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/WHLSL_ToyTests.m b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/WHLSL_ToyTests.m >new file mode 100644 >index 0000000000000000000000000000000000000000..c8deefb48ee622da0a150e7760e6b6ea173c5625 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSL Tests/WHLSL ToyTests/WHLSL_ToyTests.m >@@ -0,0 +1,68 @@ >+// >+// WHLSL_ToyTests.m >+// WHLSL ToyTests >+// >+// Created by Thomas Denney on 7/10/18. >+// Copyright © 2018 Apple, Inc. All rights reserved. >+// >+ >+#import <XCTest/XCTest.h> >+ >+#import "TestFamily.h" >+#import "TestFamilyRunner.h" >+ >+/// The actual implementation of tests is in Test.h/m >+@interface WHLSLShaderTest : XCTestCase >+ >+@end >+ >+@implementation WHLSLShaderTest >+ >++ (WHLSLShaderTest*)testCaseInstanceFromImplementation:(TestFamily*)test >+{ >+ NSMethodSignature *testSignature = [WHLSLShaderTest instanceMethodSignatureForSelector:@selector(testShaderCompilationAndExecution:)]; >+ NSInvocation *testInvocation = [NSInvocation invocationWithMethodSignature:testSignature]; >+ testInvocation.selector = @selector(testShaderCompilationAndExecution:); >+ [testInvocation setArgument:&test atIndex:2]; >+ [testInvocation retainArguments]; >+ >+ WHLSLShaderTest *testCase = [[WHLSLShaderTest alloc] initWithInvocation:testInvocation]; >+ return testCase; >+} >+ >+- (void)testShaderCompilationAndExecution:(TestFamily*)test { >+ // Xcode gives each test case instance the same name (based on the method signature) >+ // As a (temporary) workaround I log the name of the test so that I can quickly identify the instance >+ NSLog(@"%@", test.name); >+ TestFamilyRunner* runner = [[TestFamilyRunner alloc] initWithTestFamily:test]; >+ BOOL result = [runner executeAllTests]; >+ if (result) >+ NSLog(@"\u2705 %@", test.name); >+ XCTAssert(result, @"%@", test.name/*, test.failureDescription*/); >+ NSLog(@"%lu", [TestFamilyRunner executionCount]); >+} >+ >+@end >+ >+@interface WHLSL_ToyTests : XCTestCase >+ >+@end >+ >+@implementation WHLSL_ToyTests >+ >++ (XCTestSuite*)defaultTestSuite >+{ >+ XCTestSuite* suite = [XCTestSuite testSuiteWithName:@"WHLSL tests"]; >+ NSArray<TestFamily*>* testDescriptions = [TestFamily allTests]; >+ NSRegularExpression* testFilter = [NSRegularExpression regularExpressionWithPattern:@"^exhaustiveUint8Switch" options:0 error:nil]; >+ for (TestFamily* test in testDescriptions) { >+ if ([testFilter firstMatchInString:test.name options:0 range:NSMakeRange(0, test.name.length)]) >+ [suite addTest:[WHLSLShaderTest testCaseInstanceFromImplementation:test]]; >+ } >+ >+ NSLog(@"Will execute %ld tests", suite.tests.count); >+ >+ return suite; >+} >+ >+@end >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/WHLSLLexer.ts b/Tools/WebGPUShadingLanguageRI/Metal/WHLSLLexer.ts >new file mode 100644 >index 0000000000000000000000000000000000000000..e82bcd126a0b9d689c2d2398972e15bed0994397 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/WHLSLLexer.ts >@@ -0,0 +1,86 @@ >+function lexWhitespaceAndComment(src, startIndex) { >+ // WHLSL permits multiline comments, but the (restricted) MSL lexer doesn't >+ const wsRegex = /^\s+/; >+ const oneLineCommentRegex = /^\/\/(.*?)(\n|$)/; >+ const multilineCommentStartRegex = /^\/\*/; >+ const multilineCommentEndRegex = /\*\//; >+ >+ const tokens: Token[] = []; >+ >+ const originalLength = src.length; >+ >+ while (src.length) { >+ const wsMatch = wsRegex.exec(src); >+ if (wsMatch) { >+ tokens.push(new Token("whitespace", wsMatch[0], originalLength - src.length + startIndex)); >+ src = src.substring(wsMatch[0].length); >+ continue; >+ } >+ >+ const oneLineCommentMatch = oneLineCommentRegex.exec(src); >+ if (oneLineCommentMatch) { >+ tokens.push(new Token("comment", oneLineCommentMatch[0], originalLength - src.length + startIndex)); >+ src = src.substring(oneLineCommentMatch[0].length); >+ continue; >+ } >+ >+ const multilineCommentStartMatch = multilineCommentStartRegex.exec(src); >+ if (multilineCommentStartMatch) { >+ const multilineCommentEndMatch = multilineCommentEndRegex.exec(src); >+ if (multilineCommentEndMatch) { >+ const index = multilineCommentEndMatch.index + 2; >+ tokens.push(new Token("comment", src.substring(0, index), originalLength - src.length + startIndex)); >+ src = src.substring(index); >+ } else { >+ throw new Error(`Multiline comment not terminated properly: '${src}'`); >+ } >+ continue; >+ } >+ >+ throw new Error(`Failed to tokenize whitespace/comment string '${src}'`); >+ } >+ >+ return tokens; >+} >+ >+function lexWHLSL(src) >+{ >+ const lexer = new Lexer("/internal/test", "user", 0, src); >+ let index = 0; >+ let hasTokens = true; >+ let tokens: Token[] = []; >+ >+ const mapWHLSLTokens = { >+ "floatLiteral": "literal", >+ "intHexLiteral": "literal", >+ "uintHexLiteral": "literal", >+ "intLiteral": "literal", >+ "uintLiteral": "literal" >+ }; >+ const identifiersThatAreTypes = new Set([ >+ "int", "uint", "float", "int32", "uint32", "uint8", "float2", "float3", "float4", "vertex", "fragment", "void", "bool" >+ ]); >+ >+ while (hasTokens) { >+ const next = lexer.next(); >+ if (next) { >+ // tokens.push(next); >+ if (next.index > index) { >+ tokens = tokens.concat(lexWhitespaceAndComment(src.substring(index, next.index), index)); >+ } >+ index = next.index + next.text.length; >+ let kind = next.kind; >+ if (kind in mapWHLSLTokens) >+ kind = mapWHLSLTokens[kind]; >+ if (kind == "identifier" && identifiersThatAreTypes.has(next.text)) >+ kind = "type"; >+ tokens.push(new Token(kind, next.text, next.index)); >+ } else { >+ hasTokens = false; >+ } >+ } >+ if (index != src.length) { >+ tokens = tokens.concat(lexWhitespaceAndComment(src.substring(index), index)); >+ } >+ return tokens; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/index.html b/Tools/WebGPUShadingLanguageRI/Metal/index.html >new file mode 100644 >index 0000000000000000000000000000000000000000..54817fc8c6644ab4eef44274cfbd608f756b489b >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/index.html >@@ -0,0 +1,439 @@ >+<!DOCTYPE html> >+<html> >+<head> >+ <title>WebGPU Shading Language (WHLSL) → Metal Shading Language</title> >+ <script src="../Node.js"></script> >+ <script src="../Type.js"></script> >+ <script src="../ReferenceType.js"></script> >+ <script src="../Value.js"></script> >+ <script src="../Expression.js"></script> >+ <script src="../Rewriter.js"></script> >+ <script src="../Visitor.js"></script> >+ <script src="../CreateLiteral.js"></script> >+ <script src="../CreateLiteralType.js"></script> >+ <script src="../PropertyAccessExpression.js"></script> >+ <script src="../SwizzleOp.js"></script> >+ >+ <script src="../AddressSpace.js"></script> >+ <script src="../AnonymousVariable.js"></script> >+ <script src="../ArrayRefType.js"></script> >+ <script src="../ArrayType.js"></script> >+ <script src="../Assignment.js"></script> >+ <script src="../AutoWrapper.js"></script> >+ <script src="../Block.js"></script> >+ <script src="../BoolLiteral.js"></script> >+ <script src="../Break.js"></script> >+ <script src="../CallExpression.js"></script> >+ <script src="../CallFunction.js"></script> >+ <script src="../Check.js"></script> >+ <script src="../CheckLiteralTypes.js"></script> >+ <script src="../CheckLoops.js"></script> >+ <script src="../CheckRecursion.js"></script> >+ <script src="../CheckRecursiveTypes.js"></script> >+ <script src="../CheckReturns.js"></script> >+ <script src="../CheckUnreachableCode.js"></script> >+ <script src="../CheckWrapped.js"></script> >+ <script src="../Checker.js"></script> >+ <script src="../CloneProgram.js"></script> >+ <script src="../CommaExpression.js"></script> >+ <script src="../ConstexprFolder.js"></script> >+ <script src="../ConstexprTypeParameter.js"></script> >+ <script src="../Continue.js"></script> >+ <script src="../ConvertPtrToArrayRefExpression.js"></script> >+ <script src="../DoWhileLoop.js"></script> >+ <script src="../DotExpression.js"></script> >+ <script src="../DereferenceExpression.js"></script> >+ <script src="../EArrayRef.js"></script> >+ <script src="../EBuffer.js"></script> >+ <script src="../EBufferBuilder.js"></script> >+ <script src="../EPtr.js"></script> >+ <script src="../EnumLiteral.js"></script> >+ <script src="../EnumMember.js"></script> >+ <script src="../EnumType.js"></script> >+ <script src="../EvaluationCommon.js"></script> >+ <script src="../Evaluator.js"></script> >+ <script src="../ExpressionFinder.js"></script> >+ <script src="../ExternalOrigin.js"></script> >+ <script src="../Field.js"></script> >+ <script src="../FindHighZombies.js"></script> >+ <script src="../FlattenProtocolExtends.js"></script> >+ <script src="../FlattenedStructOffsetGatherer.js"></script> >+ <script src="../FloatLiteral.js"></script> >+ <script src="../FloatLiteralType.js"></script> >+ <script src="../FoldConstexprs.js"></script> >+ <script src="../ForLoop.js"></script> >+ <script src="../Func.js"></script> >+ <script src="../FuncDef.js"></script> >+ <script src="../FuncInstantiator.js"></script> >+ <script src="../FuncParameter.js"></script> >+ <script src="../FunctionLikeBlock.js"></script> >+ <script src="../HighZombieFinder.js"></script> >+ <script src="../IdentityExpression.js"></script> >+ <script src="../IfStatement.js"></script> >+ <script src="../IndexExpression.js"></script> >+ <script src="../InferTypesForCall.js"></script> >+ <script src="../Inline.js"></script> >+ <script src="../Inliner.js"></script> >+ <script src="../InstantiateImmediates.js"></script> >+ <script src="../IntLiteral.js"></script> >+ <script src="../IntLiteralType.js"></script> >+ <script src="../Intrinsics.js"></script> >+ <script src="../LateChecker.js"></script> >+ <script src="../Lexer.js"></script> >+ <script src="../LexerToken.js"></script> >+ <script src="../LiteralTypeChecker.js"></script> >+ <script src="../LogicalExpression.js"></script> >+ <script src="../LogicalNot.js"></script> >+ <script src="../LoopChecker.js"></script> >+ <script src="../MakeArrayRefExpression.js"></script> >+ <script src="../MakePtrExpression.js"></script> >+ <script src="../NameContext.js"></script> >+ <script src="../NameFinder.js"></script> >+ <script src="../NameResolver.js"></script> >+ <script src="../NativeFunc.js"></script> >+ <script src="../NativeFuncInstance.js"></script> >+ <script src="../NativeType.js"></script> >+ <script src="../NativeTypeInstance.js"></script> >+ <script src="../NormalUsePropertyResolver.js"></script> >+ <script src="../NullLiteral.js"></script> >+ <script src="../NullType.js"></script> >+ <script src="../OriginKind.js"></script> >+ <script src="../OverloadResolutionFailure.js"></script> >+ <script src="../Parse.js"></script> >+ <script src="../Prepare.js"></script> >+ <script src="../PropertyResolver.js"></script> >+ <script src="../Program.js"></script> >+ <script src="../ProgramWithUnnecessaryThingsRemoved.js"></script> >+ <script src="../Protocol.js"></script> >+ <script src="../ProtocolDecl.js"></script> >+ <script src="../ProtocolFuncDecl.js"></script> >+ <script src="../ProtocolRef.js"></script> >+ <script src="../PtrType.js"></script> >+ <script src="../ReadModifyWriteExpression.js"></script> >+ <script src="../RecursionChecker.js"></script> >+ <script src="../RecursiveTypeChecker.js"></script> >+ <script src="../ResolveNames.js"></script> >+ <script src="../ResolveOverloadImpl.js"></script> >+ <script src="../ResolveProperties.js"></script> >+ <script src="../ResolveTypeDefs.js"></script> >+ <script src="../Return.js"></script> >+ <script src="../ReturnChecker.js"></script> >+ <script src="../ReturnException.js"></script> >+ <script src="../StandardLibrary.js"></script> >+ <script src="../StatementCloner.js"></script> >+ <script src="../StructLayoutBuilder.js"></script> >+ <script src="../StructType.js"></script> >+ <script src="../Substitution.js"></script> >+ <script src="../SwitchCase.js"></script> >+ <script src="../SwitchStatement.js"></script> >+ <script src="../SynthesizeEnumFunctions.js"></script> >+ <script src="../SynthesizeStructAccessors.js"></script> >+ <script src="../TrapStatement.js"></script> >+ <script src="../TypeDef.js"></script> >+ <script src="../TypeDefResolver.js"></script> >+ <script src="../TypeOrVariableRef.js"></script> >+ <script src="../TypeParameterRewriter.js"></script> >+ <script src="../TypeRef.js"></script> >+ <script src="../TypeVariable.js"></script> >+ <script src="../TypeVariableTracker.js"></script> >+ <script src="../TypedValue.js"></script> >+ <script src="../UintLiteral.js"></script> >+ <script src="../UintLiteralType.js"></script> >+ <script src="../UnificationContext.js"></script> >+ <script src="../UnreachableCodeChecker.js"></script> >+ <script src="../VariableDecl.js"></script> >+ <script src="../VariableRef.js"></script> >+ <script src="../VisitingSet.js"></script> >+ <script src="../WSyntaxError.js"></script> >+ <script src="../WTrapError.js"></script> >+ <script src="../WTypeError.js"></script> >+ <script src="../WhileLoop.js"></script> >+ <script src="../WrapChecker.js"></script> >+ >+<script src="compiler.js"></script> >+ >+<link rel="stylesheet" type="text/css" href="metal.css" /> >+ >+<script> >+let defaultShaderSource = `struct VertexInput { >+ float2 position; >+ float3 color; >+} >+ >+struct VertexOutput { >+ float4 wsl_Position; >+ float3 color; >+} >+ >+struct FragmentOutput { >+ float4 wsl_Color; >+} >+ >+vertex VertexOutput vertexShader(VertexInput vertexInput) { >+ VertexOutput result; >+ result.wsl_Position = float4(vertexInput.position, 0., 1.); >+ result.color = vertexInput.color; >+ return result; >+} >+ >+fragment FragmentOutput fragmentShader(VertexOutput stageIn) { >+ FragmentOutput result; >+ result.wsl_Color = float4(stageIn.color, 1.); >+ return result; >+}`; >+ >+let whlslContainer; >+let mslContainer; >+ >+let whlslSourceView; >+let mslSourceView; >+ >+const LocalStorageWhlslKeyName = "ShaderSource"; >+const LocalStorageMslKeyName = "ShaderMSLResult"; >+ >+window.addEventListener("load", () => { >+ mslContainer = document.getElementById("MetalOutput"); >+ mslSourceView = new SourceView("MSL (previous compilation)", mslContainer, (src) => new MSLLexer(src).tokens); >+ >+ try { >+ const localStorage = window.localStorage; >+ const mslSource = localStorage.getItem(LocalStorageMslKeyName); >+ mslSourceView.src = mslSource; >+ } catch(e) { >+ } >+ >+ whlslContainer = document.getElementById("WHLSLInput"); >+ whlslSourceView = new SourceView("WHLSL", whlslContainer, lexWHLSL, compileWHLSL, true); >+ >+ try { >+ const localStorage = window.localStorage; >+ let whlslSource = localStorage.getItem(LocalStorageWhlslKeyName); >+ if (!whlslSource) >+ whlslSource = defaultShaderSource; >+ whlslSourceView.src = whlslSource; >+ whlslSourceView.compile(); >+ } catch (e) { >+ console.log(e); >+ } >+}); >+ >+function compileWHLSL(src) { >+ window.localStorage.setItem(LocalStorageWhlslKeyName, src); >+ const compileResult = whlslToMsl(src); >+ >+ if (compileResult.didSucceed) { >+ mslSourceView.src = compileResult.metalShaderLanguageSource; >+ mslSourceView.name = "MSL"; >+ >+ const copyMap = compileResult.functionSources; >+ copyMap.set("MSL", compileResult.metalShaderLanguageSource); >+ mslSourceView.copySources = copyMap; >+ console.log(copyMap); >+ >+ window.localStorage.setItem(LocalStorageMslKeyName, compileResult.metalShaderLanguageSource); >+ } else { >+ mslSourceView.name = "MSL (previous compilation)"; >+ whlslSourceView.errorText = compileResult.error.message; >+ } >+} >+ >+// Wraps a textarea and a bunch of buttons >+class SourceView { >+ constructor(name, container, lexer, compiler = null, editable = false) >+ { >+ this._name = name; >+ this._container = container; >+ this._lexingDelegate = lexer; >+ this._compiler = compiler; >+ this._copySources = new Map(); >+ this._src = ""; >+ this._tokens = []; >+ this._editable = editable; >+ this._errorText = ""; >+ } >+ >+ get name() { return this._name; } >+ get editable() { return this._editable; } >+ get src() { return this._src; } >+ >+ set src(newSrc) >+ { >+ this._src = newSrc; >+ this._tokens = this._lexingDelegate(this._src); >+ this._updateView(); >+ } >+ >+ get copySources() { return this._copySources; } >+ set copySources(cs) >+ { >+ this._copySources = cs; >+ this._updateView(); >+ } >+ >+ get errorText() { return this._errorText; } >+ >+ set errorText(newErrorText) >+ { >+ this._errorText = newErrorText; >+ if (this._errorBox && newErrorText) >+ this._errorBox.innerText = this._errorText; >+ } >+ >+ set name(newName) >+ { >+ this._name = newName; >+ if (this._header) >+ this._header.innerText = this.name; >+ } >+ >+ _updateView() >+ { >+ this._presentSource(this._tokens, this._container); >+ } >+ >+ _removeAllChildren(node) >+ { >+ while (node.hasChildNodes()) { >+ node.removeChild(node.lastChild); >+ } >+ } >+ >+ _splitTokensIntoLines(tokens) >+ { >+ const lines = []; >+ let currentLine = []; >+ lines.push(currentLine); >+ >+ for (let tok of tokens) { >+ let tokSections = tok.src.split('\n'); >+ for (let i = 0; i < tokSections.length; i++) { >+ let tokSection = tokSections[i]; >+ >+ let span = document.createElement('span'); >+ span.innerText = tokSection; >+ span.className = `code-${tok.type}`; >+ currentLine.push(span); >+ >+ if (i != tokSections.length - 1) { >+ currentLine = []; >+ lines.push(currentLine); >+ } >+ } >+ } >+ >+ return lines; >+ } >+ >+ _presentSource(tokens, container) >+ { >+ this._removeAllChildren(container); >+ >+ this._header = document.createElement('h2'); >+ this._header.innerText = this.name; >+ container.appendChild(this._header); >+ >+ const lines = this._splitTokensIntoLines(tokens); >+ >+ const srcTable = document.createElement('table'); >+ srcTable.className = 'code-source'; >+ >+ for (let i = 0; i < lines.length; i++) { >+ const currentRow = document.createElement('tr'); >+ >+ const currentLineNumber = document.createElement('td'); >+ currentLineNumber.className = 'line-no'; >+ currentLineNumber.dataset.content = (i + 1).toString(); // line-no shown with CSS >+ currentRow.appendChild(currentLineNumber); >+ >+ const currentLineElement = document.createElement('td'); >+ currentLineElement.className = 'line'; >+ for (let span of lines[i]) { >+ currentLineElement.appendChild(span); >+ } >+ currentRow.appendChild(currentLineElement); >+ >+ srcTable.appendChild(currentRow); >+ } >+ >+ container.appendChild(srcTable); >+ >+ if (this.editable) { >+ const editButton = document.createElement('input'); >+ editButton.type = "button"; >+ editButton.value = "Edit"; >+ editButton.addEventListener("click", () => this.edit()); >+ container.appendChild(editButton); >+ } >+ >+ for (let [name, source] of this.copySources) { >+ const copyButton = document.createElement('input'); >+ copyButton.type = "button"; >+ copyButton.value = `Copy ${name}`; >+ copyButton.addEventListener("click", () => { >+ const fakeTextarea = document.createElement('textarea'); >+ fakeTextarea.value = source; >+ document.body.appendChild(fakeTextarea); >+ fakeTextarea.focus(); >+ fakeTextarea.select(); >+ document.execCommand("copy"); >+ document.body.removeChild(fakeTextarea); >+ }); >+ container.appendChild(copyButton); >+ } >+ >+ this._createErrorBox(); >+ } >+ >+ edit() >+ { >+ this._removeAllChildren(this._container); >+ >+ this._header = document.createElement('h2'); >+ this._header.innerText = this.name; >+ this._container.appendChild(this._header); >+ >+ this._textarea = document.createElement('textarea'); >+ this._textarea.value = this.src; >+ this._container.appendChild(this._textarea); >+ >+ const compileButton = document.createElement('input'); >+ compileButton.type = "button"; >+ compileButton.value = "Compile"; >+ compileButton.addEventListener("click", () => this.compile()); >+ this._container.appendChild(compileButton); >+ >+ this._createErrorBox(); >+ } >+ >+ _createErrorBox() >+ { >+ this._errorBox = document.createElement('div'); >+ if (this.errorText) { >+ this._errorBox.innerText = this.errorText; >+ this._errorText = null; >+ } >+ this._container.appendChild(this._errorBox); >+ } >+ >+ compile() >+ { >+ let src = this._textarea ? this._textarea.value : this._src; >+ this._compiler(src); >+ this.src = src; >+ } >+} >+</script> >+</head> >+<body> >+<table cellspacing="0" cellpadding="0"> >+ <tr> >+ <td class="container-cell"> >+ <div id="WHLSLInput"></div> >+ </td> >+ <td class="container-cell"> >+ <div id="MetalOutput"></div> >+ </td> >+ </tr> >+</table> >+</body> >+</html> >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/metal.css b/Tools/WebGPUShadingLanguageRI/Metal/metal.css >new file mode 100644 >index 0000000000000000000000000000000000000000..d315d02232c6244a8c1597461ee88c00db6d2c55 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/metal.css >@@ -0,0 +1,113 @@ >+textarea, .code-source { >+ font-family: "SF Mono", monospace; >+ font-size: 11pt; >+ padding: 5px; >+ width: 800px; >+ height: 800px; >+ margin: 1em 0; >+ display: block; >+} >+ >+input[type=button] { >+ font-size: 16pt; >+} >+ >+.code-source { >+ overflow-x: scroll; >+ overflow-y: scroll; >+ border: 1px solid black; >+ display: block; >+ background-color: #1F1F24; >+ color: white; >+ white-space: nowrap; >+} >+ >+td { >+ border: 1px solid black; >+} >+ >+body { >+ font-family: -apple-system, sans-serif; >+} >+ >+h1, h2 { >+ text-align: center; >+} >+ >+table { >+ width:100%; >+ border:none; >+ border-collapse: collapse; >+ >+} >+ >+.container-cell { >+ width:50%; >+} >+ >+th, td { >+ border:none; >+ vertical-align:top; >+ margin: 0; >+ -webkit-border-horizontal-spacing: 0px; >+ -webkit-border-vertical-spacing: 0px; >+ border-collapse: collapse; >+ box-sizing: border-box; >+ border-spacing: 0; >+} >+ >+.code-comment { >+ color: #9e9e9e; >+ font-style: italic; >+ white-space: pre; >+} >+ >+.code-comment-note { >+ color: #F4E218; >+ font-style: italic; >+ font-weight:bold; >+} >+ >+.code-keyword, .code-type { >+ color: #FD5FA2; >+ font-weight: bold; >+} >+ >+.code-literal { >+ color: #9686F5; >+} >+ >+.code-attribute { >+ color: #AEF29D; >+ font-weight: bold; >+} >+ >+.code-whitespace { >+ white-space: pre; >+} >+ >+.code-error { >+ color: #fc5a3a; >+ text-decoration: underline; >+} >+ >+.code-directive { >+ color: #FC8F3F; >+} >+ >+.line-no { >+ color: #616065; >+ text-align: right; >+ -webkit-user-select:none; >+ padding-left: 5px; >+ padding-right: 5px; >+ border-right: 1px solid #616065; >+} >+ >+.line-no::before { >+ content: attr(data-content); >+} >+ >+.line { >+ padding-left: 5px; >+} >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Metal/tsconfig.json b/Tools/WebGPUShadingLanguageRI/Metal/tsconfig.json >new file mode 100644 >index 0000000000000000000000000000000000000000..04f370c3827a319a7c27e1803f0e4740ed7fcd88 >--- /dev/null >+++ b/Tools/WebGPUShadingLanguageRI/Metal/tsconfig.json >@@ -0,0 +1,26 @@ >+{ >+ "version": "2.0.0", >+ "tasks": [ >+ { >+ "type": "typescript", >+ "tsconfig": "tsconfig.json", >+ "problemMatcher": [ >+ "$tsc" >+ ], >+ "group": { >+ "kind": "build", >+ "isDefault": true >+ } >+ } >+ ], >+ "compilerOptions": { >+ "target": "es6", >+ "module": "amd", >+ "sourceMap": true, >+ "lib": [ >+ "es6" >+ ], >+ "types": [], >+ "outFile": "compiler.js" >+ } >+} >diff --git a/Tools/WebGPUShadingLanguageRI/RecursionChecker.js b/Tools/WebGPUShadingLanguageRI/RecursionChecker.js >index 5981dfbf531242ce9305b9f9a3cfe02c46179cc9..c8f8661947ff533dfa92fac2b03a27dee7715f64 100644 >--- a/Tools/WebGPUShadingLanguageRI/RecursionChecker.js >+++ b/Tools/WebGPUShadingLanguageRI/RecursionChecker.js >@@ -33,7 +33,8 @@ class RecursionChecker extends Visitor { > > visitFuncDef(node) > { >- this._visiting.doVisit(node, () => super.visitFuncDef(node)); >+ if (this._visiting.shouldVisit(node)) >+ super.visitFuncDef(node); > } > > visitCallExpression(node) >diff --git a/Tools/WebGPUShadingLanguageRI/StandardLibrary.js b/Tools/WebGPUShadingLanguageRI/StandardLibrary.js >index 1988723c3548081c667fac7862f40267f9f8b857..f5721027ec469dc3e10b7b62ad6c428b8ba6c003 100644 >--- a/Tools/WebGPUShadingLanguageRI/StandardLibrary.js >+++ b/Tools/WebGPUShadingLanguageRI/StandardLibrary.js >@@ -366,6 +366,12 @@ uint operator.length<T, uint length>(T[length]) > { > return length; > } >+ >+native float log(float); >+native float pow(float, float); >+native float sin(float); >+native float cos(float); >+native float atan2(float, float); > `; > > function intToString(x) >@@ -385,5 +391,4 @@ function intToString(x) > } > > // There are 481 swizzle operators, so we compile them as native functions >-standardLibrary += SwizzleOp.allSwizzleOperators().join(";\n") + ";"; >-console.log(standardLibrary); >\ No newline at end of file >+standardLibrary += SwizzleOp.allSwizzleOperators().join(";\n") + ";"; >\ No newline at end of file >diff --git a/Tools/WebGPUShadingLanguageRI/Test.js b/Tools/WebGPUShadingLanguageRI/Test.js >index 322a0a717850d73290848e93bf95bd3a24241c66..4be2821a16a8e41c04e0665bca985268670082e3 100644 >--- a/Tools/WebGPUShadingLanguageRI/Test.js >+++ b/Tools/WebGPUShadingLanguageRI/Test.js >@@ -32,7 +32,7 @@ if (this.window) { > window.scrollTo(0,document.body.scrollHeight); > }; > this.preciseTime = () => performance.now() / 1000; >-} else >+} else if (this.load) > load("All.js"); > > function doPrep(code) >@@ -944,13 +944,13 @@ tests.passNullToPtrPolymorphicArrayRef = function() > tests.returnIntLiteralUint = function() > { > let program = doPrep("uint foo() { return 42; }"); >- checkNumber(program, callFunction(program, "foo", [], []), 42); >+ checkUint(program, callFunction(program, "foo", [], []), 42); > } > > tests.returnIntLiteralFloat = function() > { > let program = doPrep("float foo() { return 42; }"); >- checkNumber(program, callFunction(program, "foo", [], []), 42); >+ checkFloat(program, callFunction(program, "foo", [], []), 42); > } > > tests.badIntLiteralForInt = function() >@@ -6572,7 +6572,7 @@ function* doTest(testFilter) > print("That took " + (after - before) * 1000 + " ms."); > } > >-if (!this.window) { >+if (!this.window && !this.runningInCocoaHost) { > Error.stackTraceLimit = Infinity; > for (let _ of doTest(testFilter)) { } > } >diff --git a/Tools/WebGPUShadingLanguageRI/VisitingSet.js b/Tools/WebGPUShadingLanguageRI/VisitingSet.js >index f6058f1345f1a56f2419989e61c85d5393daae5d..bdbc6aefd376a2f2041150a0861950f87d8d85d6 100644 >--- a/Tools/WebGPUShadingLanguageRI/VisitingSet.js >+++ b/Tools/WebGPUShadingLanguageRI/VisitingSet.js >@@ -29,6 +29,14 @@ class VisitingSet { > { > this._set = new Set(items); > } >+ >+ shouldVisit(item) >+ { >+ if (this._set.has(item)) >+ return false; >+ this._set.add(item); >+ return true; >+ } > > doVisit(item, callback) > {
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 187738
:
345192
|
345267
|
346955
|
347094
|
347104
|
347142
|
348258
|
348410
|
348702
|
349746
|
349818
|
350453
|
350779