WSL should support loading from arrays
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Sep 2017 02:52:14 +0000 (02:52 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Sep 2017 02:52:14 +0000 (02:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=176207

Reviewed by Saam Barati.

Getting a test that loads from arrays to work required doing a lot of things:

- a[i] now parses to ^(operator\[](a, i)).
- added operator\[] for four array reference types.
- to make thread|threadgroup|device T[] work, you need T:primitive.
- so this adds the magical primitive protocol.

This required a little bit of rejuggling in the name resolver and type checker. The main thing
is that to prevent the rewriter from copying the types referenced by some function, you need to
make sure that when you add a reference to a type, you wrap it in a TypeRef. This doesn't
completely feel right, but I'm sure we'll figure out the balance eventually. See bug 176208.

* WebGPUShadingLanguageRI/All.js:
* WebGPUShadingLanguageRI/Checker.js:
(Checker.prototype.visitProtocolDecl.set throw):
* WebGPUShadingLanguageRI/EArrayRef.js: Added.
(EArrayRef):
(EArrayRef.prototype.get ptr):
(EArrayRef.prototype.get length):
(EArrayRef.prototype.toString):
* WebGPUShadingLanguageRI/EPtr.js:
(EPtr.prototype.plus):
(EPtr.prototype.toString):
(EPtr):
* WebGPUShadingLanguageRI/Evaluator.js:
(Evaluator.prototype.visitUintLiteral):
* WebGPUShadingLanguageRI/FuncInstantiator.js:
(FuncInstantiator.prototype.getUnique.Instantiate.prototype.visitNativeFunc):
(FuncInstantiator.prototype.getUnique.Instantiate):
(FuncInstantiator.prototype.getUnique):
(FuncInstantiator):
* WebGPUShadingLanguageRI/Intrinsics.js:
(Intrinsics):
* WebGPUShadingLanguageRI/Lexer.js:
(Lexer.prototype.next):
(Lexer):
* WebGPUShadingLanguageRI/NameContext.js:
(NameContext.prototype.recognizeIntrinsics):
* WebGPUShadingLanguageRI/NameResolver.js:
(NameResolver.prototype.visitProtocolRef):
* WebGPUShadingLanguageRI/NativeFuncInstance.js:
(NativeFuncInstance.prototype.get isNative):
* WebGPUShadingLanguageRI/Parse.js:
(parseTerm):
(parseTypeDef):
(parseNative):
(parsePossibleSuffix):
(parse):
* WebGPUShadingLanguageRI/ProtocolDecl.js:
(ProtocolDecl):
* WebGPUShadingLanguageRI/ProtocolRef.js:
(ProtocolRef.prototype.get isPrimitive):
(ProtocolRef):
* WebGPUShadingLanguageRI/PtrType.js:
(PtrType.prototype.populateDefaultValue): Deleted.
* WebGPUShadingLanguageRI/ReferenceType.js:
(ReferenceType.prototype.populateDefaultValue):
(ReferenceType):
* WebGPUShadingLanguageRI/Rewriter.js:
(Rewriter.prototype.visitUintLiteral):
(Rewriter.prototype.visitFunc): Deleted.
(Rewriter.prototype.visitTypeVariable): Deleted.
(Rewriter.prototype.visitConstexprTypeParameter): Deleted.
* WebGPUShadingLanguageRI/StandardLibrary.js:
* WebGPUShadingLanguageRI/Test.js:
(TEST_threadArrayLoad):
(TEST_deviceArrayLoad):
* WebGPUShadingLanguageRI/TypeRef.js:
(TypeRef.prototype.get instantiatedType):
* WebGPUShadingLanguageRI/TypeVariable.js:
(TypeVariable.prototype.toString):
(TypeVariable):
* WebGPUShadingLanguageRI/UintLiteral.js: Added.
(UintLiteral):
(UintLiteral.prototype.get value):
(UintLiteral.prototype.get isConstexpr):
(UintLiteral.prototype.toString):
* WebGPUShadingLanguageRI/Visitor.js:
(Visitor.prototype.visitNativeFuncInstance):
(Visitor.prototype.visitTypeVariable):
(Visitor.prototype.visitPtrType):
(Visitor.prototype.visitArrayRefType):
(Visitor.prototype.visitUintLiteral):
* WebGPUShadingLanguageRI/WTrapError.js: Added.
(WTrapError):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@221468 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
Tools/ChangeLog
Tools/WebGPUShadingLanguageRI/All.js
Tools/WebGPUShadingLanguageRI/Checker.js
Tools/WebGPUShadingLanguageRI/EArrayRef.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/EPtr.js
Tools/WebGPUShadingLanguageRI/Evaluator.js
Tools/WebGPUShadingLanguageRI/FuncInstantiator.js
Tools/WebGPUShadingLanguageRI/Intrinsics.js
Tools/WebGPUShadingLanguageRI/Lexer.js
Tools/WebGPUShadingLanguageRI/NameContext.js
Tools/WebGPUShadingLanguageRI/NameResolver.js
Tools/WebGPUShadingLanguageRI/NativeFuncInstance.js
Tools/WebGPUShadingLanguageRI/Parse.js
Tools/WebGPUShadingLanguageRI/ProtocolDecl.js
Tools/WebGPUShadingLanguageRI/ProtocolRef.js
Tools/WebGPUShadingLanguageRI/PtrType.js
Tools/WebGPUShadingLanguageRI/ReferenceType.js
Tools/WebGPUShadingLanguageRI/Rewriter.js
Tools/WebGPUShadingLanguageRI/StandardLibrary.js
Tools/WebGPUShadingLanguageRI/Test.js
Tools/WebGPUShadingLanguageRI/TypeRef.js
Tools/WebGPUShadingLanguageRI/TypeVariable.js
Tools/WebGPUShadingLanguageRI/UintLiteral.js [new file with mode: 0644]
Tools/WebGPUShadingLanguageRI/Visitor.js
Tools/WebGPUShadingLanguageRI/WTrapError.js [new file with mode: 0644]

index 9a715e8..33b2b3a 100644 (file)
@@ -1,3 +1,96 @@
+2017-08-31  Filip Pizlo  <fpizlo@apple.com>
+
+        WSL should support loading from arrays
+        https://bugs.webkit.org/show_bug.cgi?id=176207
+
+        Reviewed by Saam Barati.
+        
+        Getting a test that loads from arrays to work required doing a lot of things:
+        
+        - a[i] now parses to ^(operator\[](a, i)).
+        - added operator\[] for four array reference types.
+        - to make thread|threadgroup|device T[] work, you need T:primitive.
+        - so this adds the magical primitive protocol.
+        
+        This required a little bit of rejuggling in the name resolver and type checker. The main thing
+        is that to prevent the rewriter from copying the types referenced by some function, you need to
+        make sure that when you add a reference to a type, you wrap it in a TypeRef. This doesn't
+        completely feel right, but I'm sure we'll figure out the balance eventually. See bug 176208.
+
+        * WebGPUShadingLanguageRI/All.js:
+        * WebGPUShadingLanguageRI/Checker.js:
+        (Checker.prototype.visitProtocolDecl.set throw):
+        * WebGPUShadingLanguageRI/EArrayRef.js: Added.
+        (EArrayRef):
+        (EArrayRef.prototype.get ptr):
+        (EArrayRef.prototype.get length):
+        (EArrayRef.prototype.toString):
+        * WebGPUShadingLanguageRI/EPtr.js:
+        (EPtr.prototype.plus):
+        (EPtr.prototype.toString):
+        (EPtr):
+        * WebGPUShadingLanguageRI/Evaluator.js:
+        (Evaluator.prototype.visitUintLiteral):
+        * WebGPUShadingLanguageRI/FuncInstantiator.js:
+        (FuncInstantiator.prototype.getUnique.Instantiate.prototype.visitNativeFunc):
+        (FuncInstantiator.prototype.getUnique.Instantiate):
+        (FuncInstantiator.prototype.getUnique):
+        (FuncInstantiator):
+        * WebGPUShadingLanguageRI/Intrinsics.js:
+        (Intrinsics):
+        * WebGPUShadingLanguageRI/Lexer.js:
+        (Lexer.prototype.next):
+        (Lexer):
+        * WebGPUShadingLanguageRI/NameContext.js:
+        (NameContext.prototype.recognizeIntrinsics):
+        * WebGPUShadingLanguageRI/NameResolver.js:
+        (NameResolver.prototype.visitProtocolRef):
+        * WebGPUShadingLanguageRI/NativeFuncInstance.js:
+        (NativeFuncInstance.prototype.get isNative):
+        * WebGPUShadingLanguageRI/Parse.js:
+        (parseTerm):
+        (parseTypeDef):
+        (parseNative):
+        (parsePossibleSuffix):
+        (parse):
+        * WebGPUShadingLanguageRI/ProtocolDecl.js:
+        (ProtocolDecl):
+        * WebGPUShadingLanguageRI/ProtocolRef.js:
+        (ProtocolRef.prototype.get isPrimitive):
+        (ProtocolRef):
+        * WebGPUShadingLanguageRI/PtrType.js:
+        (PtrType.prototype.populateDefaultValue): Deleted.
+        * WebGPUShadingLanguageRI/ReferenceType.js:
+        (ReferenceType.prototype.populateDefaultValue):
+        (ReferenceType):
+        * WebGPUShadingLanguageRI/Rewriter.js:
+        (Rewriter.prototype.visitUintLiteral):
+        (Rewriter.prototype.visitFunc): Deleted.
+        (Rewriter.prototype.visitTypeVariable): Deleted.
+        (Rewriter.prototype.visitConstexprTypeParameter): Deleted.
+        * WebGPUShadingLanguageRI/StandardLibrary.js:
+        * WebGPUShadingLanguageRI/Test.js:
+        (TEST_threadArrayLoad):
+        (TEST_deviceArrayLoad):
+        * WebGPUShadingLanguageRI/TypeRef.js:
+        (TypeRef.prototype.get instantiatedType):
+        * WebGPUShadingLanguageRI/TypeVariable.js:
+        (TypeVariable.prototype.toString):
+        (TypeVariable):
+        * WebGPUShadingLanguageRI/UintLiteral.js: Added.
+        (UintLiteral):
+        (UintLiteral.prototype.get value):
+        (UintLiteral.prototype.get isConstexpr):
+        (UintLiteral.prototype.toString):
+        * WebGPUShadingLanguageRI/Visitor.js:
+        (Visitor.prototype.visitNativeFuncInstance):
+        (Visitor.prototype.visitTypeVariable):
+        (Visitor.prototype.visitPtrType):
+        (Visitor.prototype.visitArrayRefType):
+        (Visitor.prototype.visitUintLiteral):
+        * WebGPUShadingLanguageRI/WTrapError.js: Added.
+        (WTrapError):
+
 2017-08-31  Alex Christensen  <achristensen@webkit.org>
 
         Add WKUIDelegatePrivate equivalent of WKPageUIClient's isPlayingAudioDidChange
index f8ae956..6b66d25 100644 (file)
@@ -45,6 +45,7 @@ load("Checker.js");
 load("CommaExpression.js");
 load("ConstexprTypeParameter.js");
 load("DereferenceExpression.js");
+load("EArrayRef.js");
 load("EBuffer.js");
 load("EBufferBuilder.js");
 load("EPtr.js");
@@ -93,9 +94,11 @@ load("TypeOrVariableRef.js");
 load("TypeRef.js");
 load("TypeVariable.js");
 load("TypedValue.js");
+load("UintLiteral.js");
 load("UnificationContext.js");
 load("VariableDecl.js");
 load("VariableRef.js");
 load("VisitingSet.js");
 load("WSyntaxError.js");
+load("WTrapError.js");
 load("WTypeError.js");
index 5abbcc5..5ae06b2 100644 (file)
@@ -100,8 +100,8 @@ class Checker extends Visitor {
         if (node.addressSpace == "thread")
             return;
         
-        if (!node.elementType.withRecursivelyInstantiatedImmediates.isPrimitive)
-            throw new WTypeError(node.origin.originString, "Illegal pointer to non-primitive type");
+        if (!node.elementType.instantiatedType.isPrimitive)
+            throw new WTypeError(node.origin.originString, "Illegal pointer to non-primitive type: " + node.elementType);
     }
     
     visitArrayType(node)
@@ -129,7 +129,7 @@ class Checker extends Visitor {
         let rhsType = node.rhs.visit(this);
         if (!lhsType.equals(rhsType))
             throw new WTypeError(node.origin.originString, "Type mismatch in assignment: " + lhsType + " versus " + rhsType);
-        node.type = lhsType;
+        node.type = TypeRef.wrap(lhsType);
         return lhsType;
     }
     
@@ -138,7 +138,7 @@ class Checker extends Visitor {
         let type = node.ptr.visit(this).unifyNode;
         if (!type.isPtr)
             throw new WTypeError(node.origin.originString, "Type passed to dereference is not a pointer: " + type);
-        node.type = type.elementType;
+        node.type = TypeRef.wrap(type.elementType);
         node.addressSpace = type.addressSpace;
         return node.type;
     }
@@ -175,9 +175,17 @@ class Checker extends Visitor {
     
     visitIntLiteral(node)
     {
+        // FIXME: This should return some kind of type variable that defaults to int but is happy to
+        // unify with uint.
+        // https://bugs.webkit.org/show_bug.cgi?id=176209
         return this._program.intrinsics.int32;
     }
     
+    visitUintLiteral(node)
+    {
+        return this._program.intrinsics.uint32;
+    }
+    
     visitCommaExpression(node)
     {
         let result = null;
diff --git a/Tools/WebGPUShadingLanguageRI/EArrayRef.js b/Tools/WebGPUShadingLanguageRI/EArrayRef.js
new file mode 100644 (file)
index 0000000..1173b17
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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. 
+ */
+"use strict";
+
+class EArrayRef {
+    constructor(ptr, length)
+    {
+        this._ptr = ptr;
+        this._length = length;
+    }
+    
+    get ptr() { return this._ptr; }
+    get length() { return this._length; }
+    
+    toString()
+    {
+        return "A:<" + this.ptr + ", " + this.length + ">";
+    }
+}
+
index bbdfd50..4b4cc34 100644 (file)
@@ -46,6 +46,11 @@ class EPtr {
     get buffer() { return this._buffer; }
     get offset() { return this._offset; }
     
+    plus(offset)
+    {
+        return new EPtr(this.buffer, this.offset + offset);
+    }
+    
     loadValue()
     {
         return this.buffer.get(this.offset);
@@ -59,8 +64,6 @@ class EPtr {
     
     toString()
     {
-        if (!this.buffer)
-            return "null";
         return "B" + this.buffer.index + ":" + this.offset;
     }
 }
index 3d1f2e8..9e5d66d 100644 (file)
@@ -121,6 +121,11 @@ class Evaluator extends Visitor {
         return EPtr.box(node.value);
     }
     
+    visitUintLiteral(node)
+    {
+        return EPtr.box(node.value);
+    }
+    
     visitCallExpression(node)
     {
         // We evaluate inlined ASTs, so this can only be a native call.
index b84af0b..ef52947 100644 (file)
@@ -71,7 +71,7 @@ class FuncInstantiator {
                 return new NativeFuncInstance(
                     func,
                     func.returnType.visit(substitution),
-                    parameters.map(parameter => parameter.visit(substitution)));
+                    func.parameters.map(parameter => parameter.visit(substitution)));
             }
         }
         let resultingFunc = func.visit(new Instantiate());
index 8dab6c7..fa94fdc 100644 (file)
 "use strict";
 
 class Intrinsics {
-    constructor()
+    constructor(nameContext)
     {
+        this.primitive = new ProtocolDecl(null, "primitive");
+        this.primitive.isPrimitive = true;
+        nameContext.add(this.primitive);
+        
         this._map = new Map();
 
         // NOTE: Intrinsic resolution happens before type name resolution, so the strings we use here
@@ -36,7 +40,7 @@ class Intrinsics {
         
         this._map.set(
             "native primitive type void<>",
-            (type) => {
+            type => {
                 this.void = type;
                 type.size = 0;
                 type.populateDefaultValue = () => { };
@@ -44,15 +48,23 @@ class Intrinsics {
 
         this._map.set(
             "native primitive type int32<>",
-            (type) => {
+            type => {
                 this.int32 = type;
                 type.size = 1;
                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
             });
 
         this._map.set(
+            "native primitive type uint32<>",
+            type => {
+                this.uint32 = type;
+                type.size = 1;
+                type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
+            });
+
+        this._map.set(
             "native primitive type double<>",
-            (type) => {
+            type => {
                 this.double = type;
                 type.size = 1;
                 type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
@@ -60,10 +72,33 @@ class Intrinsics {
         
         this._map.set(
             "native int operator+<>(int,int)",
-            (func) => {
-                func.implementation =
-                    ([left, right]) => EPtr.box((left.loadValue() + right.loadValue()) | 0);
+            func => {
+                func.implementation = ([left, right]) =>
+                    EPtr.box((left.loadValue() + right.loadValue()) | 0);
             });
+        
+        let arrayElementPtr = func => {
+            func.implementation = ([ref, index], node) => {
+                ref = ref.loadValue();
+                index = index.loadValue();
+                if (index > ref.length)
+                    throw new WTrapError(node.origin.originString, "Array index " + index + " is out of bounds of " + ref);
+                return EPtr.box(ref.ptr.plus(index * node.actualTypeArguments[0].size));
+            };
+        };
+        
+        this._map.set(
+            "native thread T^ operator\\[]<T>(thread T[],uint)",
+            arrayElementPtr);
+        this._map.set(
+            "native threadgroup T^ operator\\[]<T:primitive>(threadgroup T[],uint)",
+            arrayElementPtr);
+        this._map.set(
+            "native device T^ operator\\[]<T:primitive>(device T[],uint)",
+            arrayElementPtr);
+        this._map.set(
+            "native constant T^ operator\\[]<T:primitive>(constant T[],uint)",
+            arrayElementPtr);
     }
     
     add(thing)
index 0857cb3..8920f1b 100644 (file)
@@ -105,6 +105,9 @@ class Lexer {
         if (/^[^\d\W]\w*/.test(relevantText))
             return result("identifier");
 
+        if (/^[0-9]+u/.test(relevantText))
+            return result("uintLiteral");
+
         if (/^[0-9]+/.test(relevantText))
             return result("intLiteral");
 
@@ -112,7 +115,7 @@ class Lexer {
         if (/^([0-9]*\.[0-9]+)|([0-9]+\.[0-9]*)/.test(relevantText))
             return result("doubleLiteral");
         
-        if (/^(struct|protocol|type|if|else|enum|continue|break|switch|case|default|for|while|do|return|sizeof|constant|device|threadgroup|thread|operator|null)/.test(relevantText))
+        if (/^(struct|protocol|typedef|if|else|enum|continue|break|switch|case|default|for|while|do|return|sizeof|constant|device|threadgroup|thread|operator|null)/.test(relevantText))
             return result("keyword");
         
         if (/^([{}()\[\]?:=+*\/,.%!~^&|<>\\;-]|->|=>|<=|==|!=|\+=|-=|\*=|\/=|%=|^=|\|=|&=)/.test(relevantText))
index 44459c1..53735a2 100644 (file)
@@ -137,7 +137,7 @@ class NameContext {
     
     recognizeIntrinsics()
     {
-        this._intrinsics = new Intrinsics();
+        this._intrinsics = new Intrinsics(this);
     }
     
     get intrinsics()
index 6267732..759b012 100644 (file)
@@ -100,6 +100,14 @@ class NameResolver extends Visitor {
             signature.visit(checker);
     }
     
+    visitProtocolRef(node)
+    {
+        let result = this._nameContext.get(Protocol, node.name);
+        if (!result)
+            throw new WTypeError(node.origin.originString, "Could not find protocol named " + node.name);
+        node.protocolDecl = result;
+    }
+    
     visitTypeDef(node)
     {
         let nameContext = new NameContext(this._nameContext);
index 4587d23..288faca 100644 (file)
@@ -32,6 +32,7 @@ class NativeFuncInstance extends Func {
     }
     
     get func() { return this._func; }
+    get isNative() { return true; }
 
     toString()
     {
index 5c5b42a..f714a4a 100644 (file)
@@ -177,6 +177,12 @@ function parse(program, origin, lineNumberOffset, text)
                 lexer.fail("Integer literal is not 32-bit integer");
             return new IntLiteral(token, intVersion);
         }
+        if (token = tryConsumeKind("uintLiteral")) {
+            let uintVersion = token.text >>> 0;
+            if (uintVersion + "u" !== token.text)
+                lexer.fail("Integer literal is not 32-bit unsigned integer");
+            return new UintLiteral(token, uintVersion);
+        }
         if (token = tryConsumeKind("doubleLiteral")) {
             token = consumeKind("doubleLiteral");
             return new DoubleLiteral(token, +token.text);
@@ -280,7 +286,7 @@ function parse(program, origin, lineNumberOffset, text)
     
     function parseTypeDef()
     {
-        let origin = consume("type");
+        let origin = consume("typedef");
         let name = consumeKind("identifier").text;
         let typeParameters = parseTypeParameters();
         consume("=");
@@ -293,10 +299,10 @@ function parse(program, origin, lineNumberOffset, text)
     {
         let origin = consume("native");
         let isType = lexer.backtrackingScope(() => {
-            if (tryConsume("type"))
+            if (tryConsume("typedef"))
                 return "normal";
             consume("primitive");
-            consume("type");
+            consume("typedef");
             return "primitive";
         });
         if (isType) {
@@ -374,7 +380,9 @@ function parse(program, origin, lineNumberOffset, text)
             case "[": {
                 let index = parseExpression();
                 consume("]");
-                left = new IndexExpression(token, left, index);
+                left = new DereferenceExpression(
+                    token,
+                    new CallExpression(token, "operator\\[]", [], [left, index]));
                 break;
             }
             default:
@@ -644,7 +652,7 @@ function parse(program, origin, lineNumberOffset, text)
             return;
         if (token.text == ";")
             lexer.next();
-        else if (token.text == "type")
+        else if (token.text == "typedef")
             program.add(parseTypeDef());
         else if (token.text == "native")
             program.add(parseNative());
index a44cd0b..a22a8e2 100644 (file)
@@ -31,6 +31,7 @@ class ProtocolDecl extends Protocol {
         this._signatures = [];
         this._signatureMap = new Map();
         this._typeVariable = new TypeVariable(origin, name, null);
+        this.isPrimitive = false;
     }
     
     addSignature(signature)
index 4978263..d3c0ea3 100644 (file)
@@ -40,4 +40,9 @@ class ProtocolRef extends Protocol {
     {
         return this.protocolDecl.hasHeir(type);
     }
+    
+    get isPrimitive()
+    {
+        return this.protocolDecl.isPrimitive;
+    }
 }
index c8ee150..008af40 100644 (file)
 class PtrType extends ReferenceType {
     get isPtr() { return true; }
     
-    populateDefaultValue(buffer, offset)
-    {
-        buffer.set(offset, null);
-    }
-    
     unifyImpl(unificationContext, other)
     {
         if (!(other instanceof PtrType))
index bceeaca..fd21099 100644 (file)
@@ -40,5 +40,10 @@ class ReferenceType extends Type {
     get isPrimitive() { return false; }
 
     get size() { return 1; }
+
+    populateDefaultValue(buffer, offset)
+    {
+        buffer.set(offset, null);
+    }
 }
 
index 0df4bc6..fb5bba1 100644 (file)
@@ -24,6 +24,9 @@
  */
 "use strict";
 
+// FIXME: This should have sensible behavior when it encounters definitions that it cannot handle. Right
+// now we are hackishly preventing this by wrapping things in TypeRef. That's probably wrong.
+// https://bugs.webkit.org/show_bug.cgi?id=176208
 class Rewriter {
     constructor()
     {
@@ -44,14 +47,6 @@ class Rewriter {
         return oldItem;
     }
     
-    visitFunc(node)
-    {
-        return new Func(
-            node.name, node.returnType.visit(this),
-            node.typeParameters.map(typeParameter => typeParameter.visit(this)),
-            node.parameters.map(parameter => parameter.visit(this)));
-    }
-    
     visitFuncParameter(node)
     {
         let result = new FuncParameter(node.origin, node.name, node.type.visit(this));
@@ -97,20 +92,12 @@ class Rewriter {
     visitTypeRef(node)
     {
         let result = new TypeRef(node.origin, node.name, node.typeArguments.map(typeArgument => typeArgument.visit(this)));
+        // We should probably visit this type.
+        // https://bugs.webkit.org/show_bug.cgi?id=176208
         result.type = node.type;
         return result;
     }
     
-    visitTypeVariable(node)
-    {
-        return node;
-    }
-    
-    visitConstexprTypeParameter(node)
-    {
-        return new ConstexprTypeParameter(node.origin, node.name, node.type.visit(this));
-    }
-    
     visitField(node)
     {
         return new Field(node.origin, node.name, node.type.visit(this));
@@ -171,6 +158,11 @@ class Rewriter {
         return node;
     }
 
+    visitUintLiteral(node)
+    {
+        return node;
+    }
+
     visitCallExpression(node)
     {
         let result = new CallExpression(
index 95c4ec1..ebdb898 100644 (file)
 // NOTE: The next line is line 28, and we rely on this in Prepare.js.
 const standardLibrary = `
 // This is the WSL standard library. Implementations of all of these things are in
-// Intrinsics.js.
+// Intrinsics.js. The only thing that gets defined before we get here is the primitive
+// protocol.
 
 // Need to bootstrap void first.
-native primitive type void;
-native primitive type int32;
-type int = int32;
+native primitive typedef void;
+
+native primitive typedef int32;
+native primitive typedef uint32;
+typedef int = int32;
+typedef uint = uint32;
 
 native int operator+(int, int);
+
+native thread T^ operator\\[]<T>(thread T[], uint);
+native threadgroup T^ operator\\[]<T:primitive>(threadgroup T[], uint);
+native device T^ operator\\[]<T:primitive>(device T[], uint);
+native constant T^ operator\\[]<T:primitive>(constant T[], uint);
 `;
index 7f1ef67..b570f8c 100644 (file)
@@ -157,6 +157,32 @@ function TEST_simpleMakePtr()
         throw new Error("Expected 42 but got: " + value);
 }
 
+function TEST_threadArrayLoad()
+{
+    let program = doPrep(`
+        int foo(thread int[] array)
+        {
+            return array[0u];
+        }`);
+    let buffer = new EBuffer(1);
+    buffer.set(0, 89);
+    let result = callFunction(program, "foo", [], [TypedValue.box(new ArrayRefType(null, "thread", program.intrinsics.int32), new EArrayRef(new EPtr(buffer, 0), 1))]);
+    checkInt(program, result, 89);
+}
+
+function TEST_deviceArrayLoad()
+{
+    let program = doPrep(`
+        int foo(device int[] array)
+        {
+            return array[0u];
+        }`);
+    let buffer = new EBuffer(1);
+    buffer.set(0, 89);
+    let result = callFunction(program, "foo", [], [TypedValue.box(new ArrayRefType(null, "device", program.intrinsics.int32), new EArrayRef(new EPtr(buffer, 0), 1))]);
+    checkInt(program, result, 89);
+}
+
 let before = preciseTime();
 
 let filter = /.*/; // run everything by default
index e507609..3da3164 100644 (file)
@@ -48,6 +48,8 @@ class TypeRef extends Type {
     get instantiatedType()
     {
         let type = this.type.unifyNode;
+        if (!this.typeArguments.length)
+            return type;
         if (!type.instantiate)
             throw new Error("type does not support instantiation: " + type + " (" + type.constructor.name + ")");
         return type.instantiate(this.typeArguments);
index bda4bcb..4dce16c 100644 (file)
@@ -93,7 +93,7 @@ class TypeVariable extends Type {
     
     toString()
     {
-        return this.name;
+        return this.name + (this.protocol ? ":" + this.protocol.name : "");
     }
 }
 
diff --git a/Tools/WebGPUShadingLanguageRI/UintLiteral.js b/Tools/WebGPUShadingLanguageRI/UintLiteral.js
new file mode 100644 (file)
index 0000000..f28d09b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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. 
+ */
+"use strict";
+
+class UintLiteral extends Expression {
+    constructor(origin, value)
+    {
+        super(origin);
+        this._value = value;
+    }
+    
+    get value() { return this._value; }
+    get isConstexpr() { return true; }
+    
+    toString()
+    {
+        return "" + this._value + "u";
+    }
+}
+
index 2cbf73b..dd063f3 100644 (file)
@@ -56,6 +56,12 @@ class Visitor {
         this.visitFunc(node);
     }
     
+    visitNativeFuncInstance(node)
+    {
+        node.func.visit(this);
+        this.visitFunc(node);
+    }
+    
     visitBlock(node)
     {
         for (let statement of node.statements)
@@ -107,6 +113,8 @@ class Visitor {
     
     visitTypeVariable(node)
     {
+        if (node.protocol)
+            node.protocol.visit(this);
     }
     
     visitConstexprTypeParameter(node)
@@ -124,14 +132,19 @@ class Visitor {
         node.elementType.visit(this);
     }
     
-    visitPtrType(node)
+    visitReferenceType(node)
     {
         this.visitElementalType(node);
     }
     
+    visitPtrType(node)
+    {
+        this.visitReferenceType(node);
+    }
+    
     visitArrayRefType(node)
     {
-        this.visitElementalType(node);
+        this.visitReferenceType(node);
     }
     
     visitArrayType(node)
@@ -177,6 +190,10 @@ class Visitor {
     {
     }
     
+    visitUintLiteral(node)
+    {
+    }
+    
     visitCallExpression(node)
     {
         for (let typeArgument of node.typeArguments)
diff --git a/Tools/WebGPUShadingLanguageRI/WTrapError.js b/Tools/WebGPUShadingLanguageRI/WTrapError.js
new file mode 100644 (file)
index 0000000..12aa8de
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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. 
+ */
+"use strict";
+
+class WTrapError extends Error {
+    constructor(originString, message)
+    {
+        super("Trap at " + originString + ": " + message);
+        this.originString = originString;
+        this.syntaxErrorMessage = message;
+    }
+}
+