Diff
Modified: trunk/Tools/ChangeLog (221592 => 221593)
--- trunk/Tools/ChangeLog 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/ChangeLog 2017-09-04 20:15:33 UTC (rev 221593)
@@ -1,5 +1,86 @@
2017-09-03 Filip Pizlo <[email protected]>
+ WSL IntLiteral should have variable type so that it can unify with things like uint
+ https://bugs.webkit.org/show_bug.cgi?id=176209
+
+ Reviewed by Mylex Maxfield.
+
+ This introduces IntLiteralType, which can unify with any number type that can represent the
+ int literal.
+
+ This means that all of the following are legal:
+
+ double x = 0; // 0 unifies with double
+ double y = x + 5; // should resolve to double+double
+ double z = array[0]; // 0 unifies with uint
+
+ We can do similar things with float literals, so that you don't have to suffix "f" all the
+ time.
+
+ I think that this is very different from what C does. C just supports implicit type
+ conversions. That's why "double x = 0" works in C. We don't do type conversions. Instead, we
+ let each literal unify itself with one type.
+
+ Also updated Test.html so that it runs again and is better at printing things.
+
+ * WebGPUShadingLanguageRI/All.js:
+ * WebGPUShadingLanguageRI/Checker.js:
+ * WebGPUShadingLanguageRI/IntLiteral.js:
+ (IntLiteral):
+ (IntLiteral.prototype.toString):
+ * WebGPUShadingLanguageRI/IntLiteralType.js: Added.
+ (IntLiteralType):
+ (IntLiteralType.prototype.get origin):
+ (IntLiteralType.prototype.get value):
+ (IntLiteralType.prototype.get isPrimitive):
+ (IntLiteralType.prototype.get isUnifiable):
+ (IntLiteralType.prototype.typeVariableUnify):
+ (IntLiteralType.prototype.unifyImpl):
+ (IntLiteralType.prototype.verifyAsArgument):
+ (IntLiteralType.prototype.verifyAsParameter):
+ (IntLiteralType.prototype.commitUnification):
+ (IntLiteralType.prototype.toString):
+ * WebGPUShadingLanguageRI/Intrinsics.js:
+ (Intrinsics.):
+ (Intrinsics):
+ * WebGPUShadingLanguageRI/LiteralTypeChecker.js:
+ (LiteralTypeChecker.prototype.visitIntLiteralType):
+ (LiteralTypeChecker):
+ * WebGPUShadingLanguageRI/NativeType.js:
+ (NativeType):
+ (NativeType.prototype.get isNumber):
+ (NativeType.prototype.set isNumber):
+ (NativeType.prototype.get isInt):
+ (NativeType.prototype.set isInt):
+ (NativeType.prototype.get isFloat):
+ (NativeType.prototype.set isFloat):
+ * WebGPUShadingLanguageRI/Prepare.js:
+ (prepare):
+ * WebGPUShadingLanguageRI/Rewriter.js:
+ (Rewriter.prototype.visitIntLiteral):
+ (Rewriter.prototype.visitIntLiteralType):
+ * WebGPUShadingLanguageRI/StandardLibrary.js:
+ * WebGPUShadingLanguageRI/Test.html:
+ * WebGPUShadingLanguageRI/Test.js:
+ (this.window.this.print):
+ (doPrep):
+ (doLex):
+ (checkNumber):
+ (checkInt):
+ (TEST_nameResolutionFailure):
+ (TEST_threadArrayLoadIntLiteral):
+ (TEST_deviceArrayStoreIntLiteral):
+ (TEST_returnIntLiteralDouble):
+ * WebGPUShadingLanguageRI/Type.js:
+ (Type.prototype.get isNumber):
+ (Type.prototype.get isInt):
+ (Type.prototype.get isFloat):
+ * WebGPUShadingLanguageRI/Visitor.js:
+ (Visitor.prototype.visitIntLiteral):
+ (Visitor.prototype.visitIntLiteralType):
+
+2017-09-03 Filip Pizlo <[email protected]>
+
Add more tests for null behavior in WSL
https://bugs.webkit.org/show_bug.cgi?id=176318
Modified: trunk/Tools/WebGPUShadingLanguageRI/All.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/All.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -65,6 +65,7 @@
load("Inliner.js");
load("InstantiateImmediates.js");
load("IntLiteral.js");
+load("IntLiteralType.js");
load("Intrinsics.js");
load("Lexer.js");
load("LexerToken.js");
Modified: trunk/Tools/WebGPUShadingLanguageRI/Checker.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -198,10 +198,7 @@
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;
+ return node.type;
}
visitUintLiteral(node)
@@ -211,7 +208,6 @@
visitNullLiteral(node)
{
- // Return the null literal's type variable.
return node.type;
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/IntLiteral.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/IntLiteral.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/IntLiteral.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -29,6 +29,7 @@
{
super(origin);
this._value = value;
+ this.type = new IntLiteralType(origin, value);
}
get value() { return this._value; }
@@ -36,7 +37,7 @@
toString()
{
- return "" + this._value;
+ return "" + this.value;
}
}
Added: trunk/Tools/WebGPUShadingLanguageRI/IntLiteralType.js (0 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/IntLiteralType.js (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/IntLiteralType.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -0,0 +1,75 @@
+/*
+ * 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 IntLiteralType extends Type {
+ constructor(origin, value)
+ {
+ super();
+ this._origin = origin;
+ this._value = value;
+ }
+
+ get origin() { return this._origin; }
+ get value() { return this._value; }
+
+ get isPrimitive() { return true; }
+ get isUnifiable() { return true; }
+
+ typeVariableUnify(unificationContext, other)
+ {
+ if (!(other instanceof Type))
+ return false;
+
+ return this._typeVariableUnifyImpl(unificationContext, other);
+ }
+
+ unifyImpl(unificationContext, other)
+ {
+ return this.typeVariableUnify(unificationContext, other);
+ }
+
+ verifyAsArgument(unificationContext)
+ {
+ let realThis = unificationContext.find(this);
+ return realThis.isNumber && realThis.canRepresent(this.value);
+ }
+
+ verifyAsParameter(unificationContext)
+ {
+ throw new Error("IntLiteralType should never be used as a type parameter");
+ }
+
+ commitUnification(unificationContext)
+ {
+ this.type = unificationContext.find(this);
+ }
+
+ toString()
+ {
+ return "intLiteralType<" + this.value + ">";
+ }
+}
+
Modified: trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/Intrinsics.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -45,11 +45,28 @@
type.size = 0;
type.populateDefaultValue = () => { };
});
+
+ function isBitwiseEquivalent(left, right)
+ {
+ let doubleArray = new Float64Array(1);
+ let intArray = new Int32Array(doubleArray.buffer);
+ doubleArray[0] = left;
+ let leftInts = Int32Array.from(intArray);
+ doubleArray[0] = right;
+ for (let i = 0; i < 2; ++i) {
+ if (leftInts[i] != intArray[i])
+ return false;
+ }
+ return true;
+ }
this._map.set(
"native primitive type int32<>",
type => {
this.int32 = type;
+ type.isInt = true;
+ type.isNumber = true;
+ type.canRepresent = value => isBitwiseEquivalent(value | 0, value);
type.size = 1;
type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
});
@@ -58,6 +75,9 @@
"native primitive type uint32<>",
type => {
this.uint32 = type;
+ type.isInt = true;
+ type.isNumber = true;
+ type.canRepresent = value => isBitwiseEquivalent(value >>> 0, value);
type.size = 1;
type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
});
@@ -67,6 +87,9 @@
type => {
this.double = type;
type.size = 1;
+ type.isFloat = true;
+ type.isNumber = true;
+ type.canRepresent = value => true;
type.populateDefaultValue = (buffer, offset) => buffer.set(offset, 0);
});
Modified: trunk/Tools/WebGPUShadingLanguageRI/LiteralTypeChecker.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/LiteralTypeChecker.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/LiteralTypeChecker.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -38,5 +38,11 @@
if (!node.type)
throw new Error("Null at " + node.origin.originString + " does not have type");
}
+
+ visitIntLiteralType(node)
+ {
+ if (!node.type)
+ throw new Error(node + " at " + node.origin.originString + " does not have type");
+ }
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/NativeType.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/NativeType.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/NativeType.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -32,6 +32,9 @@
this._name = name;
this._isPrimitive = isPrimitive;
this._typeParameters = typeParameters;
+ this._isNumber = false;
+ this._isInt = false;
+ this._isFloat = false;
}
get origin() { return this._origin; }
@@ -40,6 +43,14 @@
get typeParameters() { return this._typeParameters; }
get isNative() { return true; }
+ // We let Intrinsics.js set these as it likes.
+ get isNumber() { return this._isNumber; }
+ set isNumber(value) { this._isNumber = value; }
+ get isInt() { return this._isInt; }
+ set isInt(value) { this._isInt = value; }
+ get isFloat() { return this._isFloat; }
+ set isFloat(value) { this._isFloat = value; }
+
instantiate(typeArguments)
{
if (typeArguments.length != this.typeParameters.length)
Modified: trunk/Tools/WebGPUShadingLanguageRI/Parse.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/Parse.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/Parse.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -172,9 +172,9 @@
if (token = tryConsumeKind("identifier"))
return new VariableRef(token, token.text);
if (token = tryConsumeKind("intLiteral")) {
- let intVersion = token.text | 0;
- if (intVersion != token.text)
- lexer.fail("Integer literal is not 32-bit integer");
+ let intVersion = Math.floor(+token.text);
+ if ("" + intVersion !== token.text)
+ lexer.fail("Integer literal is not an integer");
return new IntLiteral(token, intVersion);
}
if (token = tryConsumeKind("uintLiteral")) {
Modified: trunk/Tools/WebGPUShadingLanguageRI/Prepare.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/Prepare.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/Prepare.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -27,7 +27,7 @@
function prepare(origin, lineNumberOffset, text)
{
let program = new Program();
- parse(program, "<stdlib>", 28, standardLibrary);
+ parse(program, "/internal/stdlib", 28, standardLibrary);
parse(program, origin, lineNumberOffset, text);
resolveNames(program);
resolveTypeDefs(program);
Modified: trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -200,8 +200,17 @@
visitIntLiteral(node)
{
- return node;
+ let result = new IntLiteral(node.origin, node.value);
+ result.type = node.type.visit(this);
+ return result;
}
+
+ visitIntLiteralType(node)
+ {
+ let result = new IntLiteralType(node.origin, node.value);
+ result.type = node.type ? node.type.visit(this) : null;
+ return result;
+ }
visitUintLiteral(node)
{
Modified: trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/StandardLibrary.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -38,6 +38,8 @@
typedef int = int32;
typedef uint = uint32;
+native primitive typedef double;
+
native int operator+(int, int);
native thread T^ operator&[]<T>(thread T[], uint);
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.html (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.html 2017-09-04 20:15:33 UTC (rev 221593)
@@ -17,11 +17,13 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -39,7 +41,9 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -51,6 +55,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -66,6 +71,7 @@
<script src=""
<script src=""
<script src=""
+<script src=""
<script src=""
<script src=""
<script src=""
@@ -86,8 +92,21 @@
<script src=""
<script src=""
+
+<script>
+function doTestInBrowser()
+{
+ try {
+ doTest(window);
+ } catch (e) {
+ print("ERROR: " + e.message);
+ print(e.stack);
+ }
+}
+</script>
+
</head>
-<body _onload_="doTest(this)">
+<body _onload_="doTestInBrowser()">
<div id="messages"></div>
</body>
</html>
Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -28,7 +28,7 @@
this.print = (text) => {
var span = document.createElement("span");
document.getElementById("messages").appendChild(span);
- span.innerHTML = text + "<br>";
+ span.innerHTML = text.replace(/ /g, " ").replace(/\n/g, "<br>") + "<br>";
};
this.preciseTime = () => performance.now() / 1000;
} else
@@ -36,12 +36,12 @@
function doPrep(code)
{
- return prepare("<test>", 0, code);
+ return prepare("/internal/test", 0, code);
}
function doLex(code)
{
- let lexer = new Lexer("<test>", 0, code);
+ let lexer = new Lexer("/internal/test", 0, code);
var result = [];
for (;;) {
let next = lexer.next();
@@ -57,13 +57,21 @@
return TypedValue.box(program.intrinsics.int32, value);
}
-function checkInt(program, result, expected)
+function checkNumber(program, result, expected)
{
- if (!result.type.equals(program.intrinsics.int32))
+ if (!result.type.isNumber)
throw new Error("Wrong result type; result: " + result);
if (result.value != expected)
throw new Error("Wrong result: " + result + " (expected " + expected + ")");
}
+
+function checkInt(program, result, expected)
+{
+ if (!result.type.equals(program.intrinsics.int32))
+ throw new Error("Wrong result type; result: " + result);
+ checkNumber(program, result, expected);
+}
+
function checkLexerToken(result, expectedIndex, expectedKind, expectedText)
{
if (result._index != expectedIndex)
@@ -105,7 +113,7 @@
{
checkFail(
() => doPrep("int foo(int x) { return x + y; }"),
- (e) => e instanceof WTypeError && e.message.indexOf("<test>:1") != -1);
+ (e) => e instanceof WTypeError && e.message.indexOf("/internal/test:1") != -1);
}
function TEST_simpleVariable()
@@ -208,6 +216,20 @@
checkInt(program, result, 89);
}
+function TEST_threadArrayLoadIntLiteral()
+{
+ let program = doPrep(`
+ int foo(thread int[] array)
+ {
+ return array[0];
+ }
+ `);
+ 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(`
@@ -264,6 +286,27 @@
throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0));
}
+function TEST_deviceArrayStoreIntLiteral()
+{
+ let program = doPrep(`
+ void foo(device int[] array, int value)
+ {
+ array[0] = value;
+ }
+ `);
+ let buffer = new EBuffer(1);
+ buffer.set(0, 15);
+ let arrayRef = TypedValue.box(
+ new ArrayRefType(null, "device", program.intrinsics.int32),
+ new EArrayRef(new EPtr(buffer, 0), 1));
+ callFunction(program, "foo", [], [arrayRef, makeInt(program, 65)]);
+ if (buffer.get(0) != 65)
+ throw new Error("Bad value stored into buffer (expected 65): " + buffer.get(0));
+ callFunction(program, "foo", [], [arrayRef, makeInt(program, -111)]);
+ if (buffer.get(0) != -111)
+ throw new Error("Bad value stored into buffer (expected -111): " + buffer.get(0));
+}
+
function TEST_simpleProtocol()
{
let program = doPrep(`
@@ -633,6 +676,20 @@
(e) => e instanceof WTrapError);
}
+function TEST_defaultInitializedNullArrayRefIntLiteral()
+{
+ let program = doPrep(`
+ int foo()
+ {
+ thread int[] p = null;
+ return p[0];
+ }
+ `);
+ checkFail(
+ () => callFunction(program, "foo", [], []),
+ (e) => e instanceof WTrapError);
+}
+
function TEST_passNullToPtrMonomorphicArrayRef()
{
let program = doPrep(`
@@ -666,6 +723,39 @@
(e) => e instanceof WTypeError);
}
+function TEST_returnIntLiteralUint()
+{
+ let program = doPrep("uint foo() { return 42; }");
+ checkNumber(program, callFunction(program, "foo", [], []), 42);
+}
+
+function TEST_returnIntLiteralDouble()
+{
+ let program = doPrep("double foo() { return 42; }");
+ checkNumber(program, callFunction(program, "foo", [], []), 42);
+}
+
+function TEST_badIntLiteralForInt()
+{
+ checkFail(
+ () => doPrep("void foo() { int x = 3000000000; }"),
+ (e) => e instanceof WTypeError);
+}
+
+function TEST_badIntLiteralForUint()
+{
+ checkFail(
+ () => doPrep("void foo() { uint x = 5000000000; }"),
+ (e) => e instanceof WTypeError);
+}
+
+function TEST_badIntLiteralForDouble()
+{
+ checkFail(
+ () => doPrep("void foo() { double x = 5000000000000000000000000000000000000; }"),
+ (e) => e instanceof WSyntaxError);
+}
+
function TEST_passNullAndNotNull()
{
let program = doPrep(`
Modified: trunk/Tools/WebGPUShadingLanguageRI/Type.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/Type.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/Type.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -29,6 +29,9 @@
get kind() { return Type; }
get isPtr() { return false; }
get isArrayRef() { return false; }
+ get isNumber() { return false; }
+ get isInt() { return false; }
+ get isFloat() { return false; }
inherits(protocol)
{
Modified: trunk/Tools/WebGPUShadingLanguageRI/Visitor.js (221592 => 221593)
--- trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-04 20:14:08 UTC (rev 221592)
+++ trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-04 20:15:33 UTC (rev 221593)
@@ -215,8 +215,15 @@
visitIntLiteral(node)
{
+ node.type.visit(this);
}
+ visitIntLiteralType(node)
+ {
+ if (node.type)
+ node.type.visit(this);
+ }
+
visitUintLiteral(node)
{
}