Title: [246875] trunk
Revision
246875
Author
[email protected]
Date
2019-06-27 01:19:54 -0700 (Thu, 27 Jun 2019)

Log Message

[WHLSL] Implement arrays and MakeArrayReference
https://bugs.webkit.org/show_bug.cgi?id=198414

Reviewed by Myles C. Maxfield.

Source/WebCore:

This patch implements WHLSL arrays. The main implementation detail is that
arrays get compiled to use Metal's array type. To make everything work, this
patch also fixes a few bugs:
- The checker now allows "operator.length" to be called on arrays. Prior to
this patch, it was just allowed on array references.

- The preserve variable lifetimes pass now looks at MakeArrayReference nodes.
Prior to this patch, it just looked at MakePointerExpression.

- We were producing the wrong type for ander arguments for indexed accesses
on array types. We were saying the argument that was produced was a reference
to an array instead of an array reference to the element type.

- The trie we compose for the reverse type hierarchy was inserting elements
into the wrong "children" vector. We were always inserting things into the
top level vector. This is wrong when we have a nesting of types > 1.

I also found a bug with having arrays of pointers when writing this patch.
Work on this will take place in a follow up: https://bugs.webkit.org/show_bug.cgi?id=199197

Tests: webgpu/whlsl-huge-array.html
       webgpu/whlsl-make-array-reference.html
       webgpu/whlsl-simple-arrays.html
       webgpu/whlsl-two-dimensional-array.html

* Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
* Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp:
(WebCore::WHLSL::Metal::writeNativeFunction):
* Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp:
(WebCore::WHLSL::Metal::TypeNamer::insert):
(WebCore::WHLSL::Metal::TypeNamer::emitUnnamedTypeDefinition):
* Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.h:
* Modules/webgpu/WHLSL/WHLSLChecker.cpp:
(WebCore::WHLSL::resolveByInstantiation):
(WebCore::WHLSL::Checker::visit):
* Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp:
(WebCore::WHLSL::EscapedVariableCollector::escapeVariableUse):
* Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp:
(WebCore::WHLSL::wrapAnderCallArgument):
(WebCore::WHLSL::anderCallArgument):
* Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt:

LayoutTests:

* webgpu/whlsl-huge-array-expected.txt: Added.
* webgpu/whlsl-huge-array.html: Added.
* webgpu/whlsl-make-array-reference-expected.txt: Added.
* webgpu/whlsl-make-array-reference.html: Added.
* webgpu/whlsl-simple-arrays-expected.txt: Added.
* webgpu/whlsl-simple-arrays.html: Added.
* webgpu/whlsl-two-dimensional-array-expected.txt: Added.
* webgpu/whlsl-two-dimensional-array.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (246874 => 246875)


--- trunk/LayoutTests/ChangeLog	2019-06-27 08:14:30 UTC (rev 246874)
+++ trunk/LayoutTests/ChangeLog	2019-06-27 08:19:54 UTC (rev 246875)
@@ -1,3 +1,19 @@
+2019-06-27  Saam Barati  <[email protected]>
+
+        [WHLSL] Implement arrays and MakeArrayReference
+        https://bugs.webkit.org/show_bug.cgi?id=198414
+
+        Reviewed by Myles C. Maxfield.
+
+        * webgpu/whlsl-huge-array-expected.txt: Added.
+        * webgpu/whlsl-huge-array.html: Added.
+        * webgpu/whlsl-make-array-reference-expected.txt: Added.
+        * webgpu/whlsl-make-array-reference.html: Added.
+        * webgpu/whlsl-simple-arrays-expected.txt: Added.
+        * webgpu/whlsl-simple-arrays.html: Added.
+        * webgpu/whlsl-two-dimensional-array-expected.txt: Added.
+        * webgpu/whlsl-two-dimensional-array.html: Added.
+
 2019-06-26  Simon Fraser  <[email protected]>
 
         [Async overflow scrolling] Fix missing or misplaced content inside overflow:scroll

Added: trunk/LayoutTests/webgpu/whlsl-huge-array-expected.txt (0 => 246875)


--- trunk/LayoutTests/webgpu/whlsl-huge-array-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-huge-array-expected.txt	2019-06-27 08:19:54 UTC (rev 246875)
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/webgpu/whlsl-huge-array.html (0 => 246875)


--- trunk/LayoutTests/webgpu/whlsl-huge-array.html	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-huge-array.html	2019-06-27 08:19:54 UTC (rev 246875)
@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<script>
+const shaderSource = `
+void fill(thread float[] array, float value) {
+    for (uint i = 0; i < array.length; i++) {
+        array[i] = value;
+    }
+}
+
+[numthreads(1, 1, 1)]
+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    float[1000] array;
+    if (array.length != 1000)
+        return;
+    for (uint i = 0; i < array.length; ++i) {
+        if (array[i] != 0)
+            return;
+    }
+
+    array[0] = 0.1337;
+    if (array[0] != 0.1337)
+        return;
+
+    thread float[] arrayPtr = @array;
+    if (arrayPtr.length != 1000)
+        return;
+
+    fill(arrayPtr, 0.1010);
+    for (uint i = 0; i < arrayPtr.length; ++i) {
+        if (arrayPtr[i] != 0.1010)
+            return;
+        if (array[i] != 0.1010)
+            return;
+    }
+
+    fill(@array, 0.0101);
+    for (uint i = 0; i < array.length; ++i) {
+        if (arrayPtr[i] != 0.0101)
+            return;
+        if (array[i] != 0.0101)
+            return;
+    }
+
+    buffer[0] = 1;
+}
+`;
+async function start(device) {
+    const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true});
+    const computeStage = {module: shaderModule, entryPoint: "computeShader"};
+
+    const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]};
+    const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor);
+    const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const computePipelineDescriptor = {computeStage, layout: pipelineLayout};
+    const computePipeline = device.createComputePipeline(computePipelineDescriptor);
+
+    const size = Int32Array.BYTES_PER_ELEMENT * 1;
+
+    const bufferDescriptor = {size, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC};
+    const buffer = device.createBuffer(bufferDescriptor);
+    const bufferArrayBuffer = await buffer.mapWriteAsync();
+    const bufferFloat32Array = new Int32Array(bufferArrayBuffer);
+    bufferFloat32Array[0] = 0;
+    buffer.unmap();
+
+    const resultsBufferDescriptor = {size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ};
+    const resultsBuffer = device.createBuffer(resultsBufferDescriptor);
+
+    const bufferBinding = {buffer: resultsBuffer, size};
+    const bindGroupBinding = {binding: 0, resource: bufferBinding};
+    const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]};
+    const bindGroup = device.createBindGroup(bindGroupDescriptor);
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    commandEncoder.copyBufferToBuffer(buffer, 0, resultsBuffer, 0, size);
+    const computePassEncoder = commandEncoder.beginComputePass();
+    computePassEncoder.setPipeline(computePipeline);
+    computePassEncoder.setBindGroup(0, bindGroup);
+    computePassEncoder.dispatch(1, 1, 1);
+    computePassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+
+    const resultsArrayBuffer = await resultsBuffer.mapReadAsync();
+    let resultsInt32Array = new Int32Array(resultsArrayBuffer);
+    if (resultsInt32Array[0] === 1)
+        testPassed("");
+    else
+        testFailed("");
+    resultsBuffer.unmap();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed("");
+    finishJSTest();
+});
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/webgpu/whlsl-make-array-reference-expected.txt (0 => 246875)


--- trunk/LayoutTests/webgpu/whlsl-make-array-reference-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-make-array-reference-expected.txt	2019-06-27 08:19:54 UTC (rev 246875)
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/webgpu/whlsl-make-array-reference.html (0 => 246875)


--- trunk/LayoutTests/webgpu/whlsl-make-array-reference.html	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-make-array-reference.html	2019-06-27 08:19:54 UTC (rev 246875)
@@ -0,0 +1,184 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<script>
+const shaderSource = `
+bool test1() {
+    int value = 42;
+    thread int[] array = @value;
+    if (array.length != 1)
+        return false;
+    if (array[0] != 42)
+        return false;
+    if (array[120213] != 0)
+        return false;
+
+    array[0] = 1337;
+    if (value != 1337)
+        return false;
+
+    return true;
+}
+
+bool test2() {
+    int value = 42;
+    thread int* ptr = &value;
+    if (*ptr != 42)
+        return false;
+
+    thread int[] array = @ptr;
+    if (array.length != 1)
+        return false;
+    if (array[0] != 42)
+        return false;
+    if (array[12374217] != 0)
+        return false;
+    
+    *ptr = 666;
+    if (*ptr != 666)
+        return false;
+    if (value != 666)
+        return false;
+    if (array.length != 1)
+        return false;
+    if (array[0] != 666)
+        return false;
+
+    array[0] = 4242;
+    if (*ptr != 4242)
+        return false;
+    if (value != 4242)
+        return false;
+    if (array[0] != 4242)
+        return false;
+    if (array.length != 1)
+        return false;
+
+    return true;
+}
+
+bool test3() {
+    int[42] x;
+    thread int[42]* arrayPtr = &x;
+    if (arrayPtr->length != 42)
+        return false;
+
+    x[41] = 666;
+    if ((*arrayPtr)[41] != 666)
+        return false;
+    if ((*arrayPtr)[0] != 0)
+        return false;
+
+    thread int[] array = @x;
+    if (array.length != 42)
+        return false;
+
+    array[0] = 1337;
+    if (x[0] != 1337)
+        return false;
+    if ((*arrayPtr)[0] != 1337)
+        return false;
+
+    return true;
+}
+
+bool test4() {
+    thread int* ptr = null;
+
+    thread int[] array = @ptr;
+    if (array.length != 0)
+        return false;
+
+    if (array[0] != 0)
+        return false;
+
+    if (array[100000] != 0)
+        return false;
+
+    return true;
+}
+
+[numthreads(1, 1, 1)]
+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    if (!test1())
+        return;
+
+    if (!test2())
+        return;
+
+    if (!test3())
+        return;
+
+    if (!test4())
+        return;
+
+    buffer[0] = 1;
+}
+`;
+async function start(device) {
+    const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true});
+    const computeStage = {module: shaderModule, entryPoint: "computeShader"};
+
+    const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]};
+    const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor);
+    const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const computePipelineDescriptor = {computeStage, layout: pipelineLayout};
+    const computePipeline = device.createComputePipeline(computePipelineDescriptor);
+
+    const size = Int32Array.BYTES_PER_ELEMENT * 1;
+
+    const bufferDescriptor = {size, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC};
+    const buffer = device.createBuffer(bufferDescriptor);
+    const bufferArrayBuffer = await buffer.mapWriteAsync();
+    const bufferFloat32Array = new Int32Array(bufferArrayBuffer);
+    bufferFloat32Array[0] = 0;
+    buffer.unmap();
+
+    const resultsBufferDescriptor = {size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ};
+    const resultsBuffer = device.createBuffer(resultsBufferDescriptor);
+
+    const bufferBinding = {buffer: resultsBuffer, size};
+    const bindGroupBinding = {binding: 0, resource: bufferBinding};
+    const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]};
+    const bindGroup = device.createBindGroup(bindGroupDescriptor);
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    commandEncoder.copyBufferToBuffer(buffer, 0, resultsBuffer, 0, size);
+    const computePassEncoder = commandEncoder.beginComputePass();
+    computePassEncoder.setPipeline(computePipeline);
+    computePassEncoder.setBindGroup(0, bindGroup);
+    computePassEncoder.dispatch(1, 1, 1);
+    computePassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+
+    const resultsArrayBuffer = await resultsBuffer.mapReadAsync();
+    let resultsInt32Array = new Int32Array(resultsArrayBuffer);
+    if (resultsInt32Array[0] === 1)
+        testPassed("");
+    else
+        testFailed("");
+    resultsBuffer.unmap();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed("");
+    finishJSTest();
+});
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/webgpu/whlsl-simple-arrays-expected.txt (0 => 246875)


--- trunk/LayoutTests/webgpu/whlsl-simple-arrays-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-simple-arrays-expected.txt	2019-06-27 08:19:54 UTC (rev 246875)
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/webgpu/whlsl-simple-arrays.html (0 => 246875)


--- trunk/LayoutTests/webgpu/whlsl-simple-arrays.html	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-simple-arrays.html	2019-06-27 08:19:54 UTC (rev 246875)
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<script>
+const shaderSource = `
+void fill(thread int[] array, int value) {
+    for (uint i = 0; i < array.length; i++) {
+        array[i] = value;
+    }
+}
+
+[numthreads(1, 1, 1)]
+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    int[42] array;
+    if (array.length != 42)
+        return;
+    for (uint i = 0; i < array.length; ++i) {
+        if (array[i] != 0)
+            return;
+    }
+
+    array[0] = 517;
+    if (array[0] != 517)
+        return;
+
+    thread int[] arrayPtr = @array;
+    if (arrayPtr.length != 42)
+        return;
+
+    int[42] array2;
+    array2 = array;
+    if (array2.length != 42)
+        return;
+    if (array2[0] != 517)
+        return;
+
+    fill(arrayPtr, 1337);
+    for (uint i = 0; i < arrayPtr.length; ++i) {
+        if (arrayPtr[i] != 1337)
+            return;
+        if (array[i] != 1337)
+            return;
+    }
+
+    if (array2[0] != 517)
+        return;
+    if (array2.length != 42)
+        return;
+    for (uint i = 1; i < array2.length; ++i) {
+        if (array2[i] != 0)
+            return;
+    }
+
+    buffer[0] = 1;
+}
+`;
+async function start(device) {
+    const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true});
+    const computeStage = {module: shaderModule, entryPoint: "computeShader"};
+
+    const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]};
+    const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor);
+    const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const computePipelineDescriptor = {computeStage, layout: pipelineLayout};
+    const computePipeline = device.createComputePipeline(computePipelineDescriptor);
+
+    const size = Int32Array.BYTES_PER_ELEMENT * 1;
+
+    const bufferDescriptor = {size, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC};
+    const buffer = device.createBuffer(bufferDescriptor);
+    const bufferArrayBuffer = await buffer.mapWriteAsync();
+    const bufferFloat32Array = new Int32Array(bufferArrayBuffer);
+    bufferFloat32Array[0] = 0;
+    buffer.unmap();
+
+    const resultsBufferDescriptor = {size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ};
+    const resultsBuffer = device.createBuffer(resultsBufferDescriptor);
+
+    const bufferBinding = {buffer: resultsBuffer, size};
+    const bindGroupBinding = {binding: 0, resource: bufferBinding};
+    const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]};
+    const bindGroup = device.createBindGroup(bindGroupDescriptor);
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    commandEncoder.copyBufferToBuffer(buffer, 0, resultsBuffer, 0, size);
+    const computePassEncoder = commandEncoder.beginComputePass();
+    computePassEncoder.setPipeline(computePipeline);
+    computePassEncoder.setBindGroup(0, bindGroup);
+    computePassEncoder.dispatch(1, 1, 1);
+    computePassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+
+    const resultsArrayBuffer = await resultsBuffer.mapReadAsync();
+    let resultsInt32Array = new Int32Array(resultsArrayBuffer);
+    if (resultsInt32Array[0] === 1)
+        testPassed("");
+    else
+        testFailed("");
+    resultsBuffer.unmap();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed("");
+    finishJSTest();
+});
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/webgpu/whlsl-two-dimensional-array-expected.txt (0 => 246875)


--- trunk/LayoutTests/webgpu/whlsl-two-dimensional-array-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-two-dimensional-array-expected.txt	2019-06-27 08:19:54 UTC (rev 246875)
@@ -0,0 +1,5 @@
+PASS 
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/webgpu/whlsl-two-dimensional-array.html (0 => 246875)


--- trunk/LayoutTests/webgpu/whlsl-two-dimensional-array.html	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-two-dimensional-array.html	2019-06-27 08:19:54 UTC (rev 246875)
@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<script>
+const shaderSource = `
+void fill(thread float[10][] array, float[10] value) {
+    for (uint i = 0; i < array.length; i++) {
+        array[i] = value;
+    }
+}
+
+void fill(thread float[] array, float value) {
+    for (uint i = 0; i < array.length; i++) {
+        array[i] = value;
+    }
+}
+
+bool contains(thread float[10][] array, float value) {
+    for (uint i = 0; i < array.length; i++) {
+        for (uint j = 0; j < array[j].length; j++) {
+            if (array[i][j] != value)
+                return false;
+        }
+    }
+    return true;
+}
+
+bool contains(thread float[] array, float value) {
+    for (uint i = 0; i < array.length; i++) {
+        if (array[i] != value)
+            return false;
+    }
+    return true;
+}
+
+[numthreads(1, 1, 1)]
+compute void computeShader(device int[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    float[10][5] array;
+    if (array.length != 5)
+        return;
+    if (!contains(@array, 0))
+        return;
+
+    for (uint i = 0; i < array.length; ++i) {
+        float[10] value;
+        fill(@value, float(i));
+        array[i] = value;
+    }
+
+    for (uint i = 0; i < array.length; ++i) {
+        float[10] value = array[i];
+        if (!contains(@value, float(i)))
+            return;
+    }
+
+    buffer[0] = 1;
+}
+`;
+async function start(device) {
+    const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true});
+    const computeStage = {module: shaderModule, entryPoint: "computeShader"};
+
+    const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]};
+    const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor);
+    const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]};
+    const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+    const computePipelineDescriptor = {computeStage, layout: pipelineLayout};
+    const computePipeline = device.createComputePipeline(computePipelineDescriptor);
+
+    const size = Int32Array.BYTES_PER_ELEMENT * 1;
+
+    const bufferDescriptor = {size, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC};
+    const buffer = device.createBuffer(bufferDescriptor);
+    const bufferArrayBuffer = await buffer.mapWriteAsync();
+    const bufferFloat32Array = new Int32Array(bufferArrayBuffer);
+    bufferFloat32Array[0] = 0;
+    buffer.unmap();
+
+    const resultsBufferDescriptor = {size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ};
+    const resultsBuffer = device.createBuffer(resultsBufferDescriptor);
+
+    const bufferBinding = {buffer: resultsBuffer, size};
+    const bindGroupBinding = {binding: 0, resource: bufferBinding};
+    const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]};
+    const bindGroup = device.createBindGroup(bindGroupDescriptor);
+
+    const commandEncoder = device.createCommandEncoder(); // {}
+    commandEncoder.copyBufferToBuffer(buffer, 0, resultsBuffer, 0, size);
+    const computePassEncoder = commandEncoder.beginComputePass();
+    computePassEncoder.setPipeline(computePipeline);
+    computePassEncoder.setBindGroup(0, bindGroup);
+    computePassEncoder.dispatch(1, 1, 1);
+    computePassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+
+    const resultsArrayBuffer = await resultsBuffer.mapReadAsync();
+    let resultsInt32Array = new Int32Array(resultsArrayBuffer);
+    if (resultsInt32Array[0] === 1)
+        testPassed("");
+    else
+        testFailed("");
+    resultsBuffer.unmap();
+}
+window.jsTestIsAsync = true;
+getBasicDevice().then(function(device) {
+    start(device).then(function() {
+        finishJSTest();
+    }, function() {
+        testFailed("");
+        finishJSTest();
+    });
+}, function() {
+    testPassed("");
+    finishJSTest();
+});
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (246874 => 246875)


--- trunk/Source/WebCore/ChangeLog	2019-06-27 08:14:30 UTC (rev 246874)
+++ trunk/Source/WebCore/ChangeLog	2019-06-27 08:19:54 UTC (rev 246875)
@@ -1,3 +1,53 @@
+2019-06-27  Saam Barati  <[email protected]>
+
+        [WHLSL] Implement arrays and MakeArrayReference
+        https://bugs.webkit.org/show_bug.cgi?id=198414
+
+        Reviewed by Myles C. Maxfield.
+
+        This patch implements WHLSL arrays. The main implementation detail is that
+        arrays get compiled to use Metal's array type. To make everything work, this
+        patch also fixes a few bugs:
+        - The checker now allows "operator.length" to be called on arrays. Prior to
+        this patch, it was just allowed on array references.
+        
+        - The preserve variable lifetimes pass now looks at MakeArrayReference nodes.
+        Prior to this patch, it just looked at MakePointerExpression.
+        
+        - We were producing the wrong type for ander arguments for indexed accesses
+        on array types. We were saying the argument that was produced was a reference
+        to an array instead of an array reference to the element type.
+        
+        - The trie we compose for the reverse type hierarchy was inserting elements
+        into the wrong "children" vector. We were always inserting things into the
+        top level vector. This is wrong when we have a nesting of types > 1.
+        
+        I also found a bug with having arrays of pointers when writing this patch.
+        Work on this will take place in a follow up: https://bugs.webkit.org/show_bug.cgi?id=199197
+
+        Tests: webgpu/whlsl-huge-array.html
+               webgpu/whlsl-make-array-reference.html
+               webgpu/whlsl-simple-arrays.html
+               webgpu/whlsl-two-dimensional-array.html
+
+        * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
+        * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp:
+        (WebCore::WHLSL::Metal::writeNativeFunction):
+        * Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp:
+        (WebCore::WHLSL::Metal::TypeNamer::insert):
+        (WebCore::WHLSL::Metal::TypeNamer::emitUnnamedTypeDefinition):
+        * Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.h:
+        * Modules/webgpu/WHLSL/WHLSLChecker.cpp:
+        (WebCore::WHLSL::resolveByInstantiation):
+        (WebCore::WHLSL::Checker::visit):
+        * Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp:
+        (WebCore::WHLSL::EscapedVariableCollector::escapeVariableUse):
+        * Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp:
+        (WebCore::WHLSL::wrapAnderCallArgument):
+        (WebCore::WHLSL::anderCallArgument):
+        * Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt:
+
 2019-06-27  Fujii Hironori  <[email protected]>
 
         [CMake] Bump cmake_minimum_required version to 3.10

Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp (246874 => 246875)


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp	2019-06-27 08:14:30 UTC (rev 246874)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp	2019-06-27 08:19:54 UTC (rev 246875)
@@ -628,16 +628,22 @@
     checkErrorAndVisit(makeArrayReferenceExpression.leftValue());
     // FIXME: This needs to be made to work. It probably should be using the last leftValue too.
     // https://bugs.webkit.org/show_bug.cgi?id=198838
-    auto lValue = takeLastValue();
     auto variableName = generateNextVariableName();
+
     auto mangledTypeName = m_typeNamer.mangledNameForType(makeArrayReferenceExpression.resolvedType());
-    if (is<AST::PointerType>(makeArrayReferenceExpression.resolvedType()))
+    if (is<AST::PointerType>(makeArrayReferenceExpression.leftValue().resolvedType())) {
+        auto ptrValue = takeLastValue();
+        m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, ";\n"));
+        m_stringBuilder.append(makeString("if (", ptrValue, ") ", variableName, " = { ", ptrValue, ", 1};\n"));
+        m_stringBuilder.append(makeString("else ", variableName, " = { nullptr, 0 };\n"));
+    } else if (is<AST::ArrayType>(makeArrayReferenceExpression.leftValue().resolvedType())) {
+        auto lValue = takeLastLeftValue();
+        auto& arrayType = downcast<AST::ArrayType>(makeArrayReferenceExpression.leftValue().resolvedType());
+        m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { ", lValue, "->data(), ", arrayType.numElements(), " };\n"));
+    } else {
+        auto lValue = takeLastLeftValue();
         m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { ", lValue, ", 1 };\n"));
-    else if (is<AST::ArrayType>(makeArrayReferenceExpression.resolvedType())) {
-        auto& arrayType = downcast<AST::ArrayType>(makeArrayReferenceExpression.resolvedType());
-        m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { &(", lValue, "[0]), ", arrayType.numElements(), " };\n"));
-    } else
-        m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { &", lValue, ", 1 };\n"));
+    }
     appendRightValue(makeArrayReferenceExpression, variableName);
 }
 

Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp (246874 => 246875)


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp	2019-06-27 08:14:30 UTC (rev 246874)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp	2019-06-27 08:19:54 UTC (rev 246875)
@@ -174,8 +174,8 @@
         auto& unnamedParameterType = downcast<AST::UnnamedType>(parameterType);
         if (is<AST::ArrayType>(unnamedParameterType)) {
             auto& arrayParameterType = downcast<AST::ArrayType>(unnamedParameterType);
-            stringBuilder.append(makeString("uint ", outputFunctionName, '(', metalParameterName, " v) {\n"));
-            stringBuilder.append(makeString("    return ", arrayParameterType.numElements(), "u;\n"));
+            stringBuilder.append(makeString("uint ", outputFunctionName, '(', metalParameterName, ") {\n"));
+            stringBuilder.append(makeString("    return ", arrayParameterType.numElements(), ";\n"));
             stringBuilder.append("}\n");
             return stringBuilder.toString();
         }
@@ -257,6 +257,7 @@
         auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
         auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
         stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " v, ", metalParameter2Name, " n) {\n"));
+        ASSERT(is<AST::ArrayReferenceType>(*nativeFunctionDeclaration.parameters()[0]->type()));
         stringBuilder.append("    if (n < v.length) return &(v.pointer[n]);\n");
         stringBuilder.append("    return nullptr;\n");
         stringBuilder.append("}\n");

Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp (246874 => 246875)


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp	2019-06-27 08:14:30 UTC (rev 246874)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp	2019-06-27 08:19:54 UTC (rev 246875)
@@ -309,7 +309,7 @@
     return makeUniqueRef<ArrayTypeNameNode>(parent, generateNextTypeName(), arrayType.numElements());
 }
 
-size_t TypeNamer::insert(AST::UnnamedType& unnamedType, Vector<UniqueRef<BaseTypeNameNode>>& types)
+BaseTypeNameNode* TypeNamer::insert(AST::UnnamedType& unnamedType, Vector<UniqueRef<BaseTypeNameNode>>& types)
 {
     Vector<UniqueRef<BaseTypeNameNode>>* vectorToInsertInto { nullptr };
     BaseTypeNameNode* parent { nullptr };
@@ -317,17 +317,14 @@
         vectorToInsertInto = &types;
         parent = nullptr;
     } else if (is<AST::PointerType>(unnamedType)) {
-        auto& item = types[insert(downcast<AST::PointerType>(unnamedType).elementType(), types)];
-        vectorToInsertInto = &item->children();
-        parent = &item;
+        parent = insert(downcast<AST::PointerType>(unnamedType).elementType(), types);
+        vectorToInsertInto = &parent->children();
     } else if (is<AST::ArrayReferenceType>(unnamedType)) {
-        auto& item = types[insert(downcast<AST::ArrayReferenceType>(unnamedType).elementType(), types)];
-        vectorToInsertInto = &item->children();
-        parent = &item;
+        parent = insert(downcast<AST::ArrayReferenceType>(unnamedType).elementType(), types);
+        vectorToInsertInto = &parent->children();
     } else {
-        auto& item = types[insert(downcast<AST::ArrayType>(unnamedType).type(), types)];
-        vectorToInsertInto = &item->children();
-        parent = &item;
+        parent = insert(downcast<AST::ArrayType>(unnamedType).type(), types);
+        vectorToInsertInto = &parent->children();
     }
     ASSERT(vectorToInsertInto);
 
@@ -339,11 +336,11 @@
             ASSERT_UNUSED(addResult, addResult.isNewEntry);
         }
         vectorToInsertInto->append(WTFMove(result));
-        return vectorToInsertInto->size() - 1;
+        return &vectorToInsertInto->last().get();
     }
     auto addResult = m_unnamedTypeMapping.add(&unnamedType, &*iterator);
     ASSERT_UNUSED(addResult, addResult.isNewEntry);
-    return iterator - vectorToInsertInto->begin();
+    return &*iterator;
 }
 
 class MetalTypeDeclarationWriter : public Visitor {
@@ -398,7 +395,7 @@
     } else {
         auto& arrayType = downcast<ArrayTypeNameNode>(baseTypeNameNode);
         ASSERT(baseTypeNameNode.parent());
-        stringBuilder.append(makeString("typedef Array<", arrayType.parent()->mangledName(), ", ", arrayType.numElements(), "> ", arrayType.mangledName(), ";\n"));
+        stringBuilder.append(makeString("typedef array<", arrayType.parent()->mangledName(), ", ", arrayType.numElements(), "> ", arrayType.mangledName(), ";\n"));
     }
     emittedUnnamedTypes.add(&baseTypeNameNode);
 }

Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.h (246874 => 246875)


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.h	2019-06-27 08:14:30 UTC (rev 246874)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.h	2019-06-27 08:19:54 UTC (rev 246875)
@@ -100,7 +100,7 @@
     String metalTypeDefinitions();
 
     UniqueRef<BaseTypeNameNode> createNameNode(AST::UnnamedType&, BaseTypeNameNode* parent);
-    size_t insert(AST::UnnamedType&, Vector<UniqueRef<BaseTypeNameNode>>&);
+    BaseTypeNameNode* insert(AST::UnnamedType&, Vector<UniqueRef<BaseTypeNameNode>>&);
 
     Program& m_program;
     Vector<UniqueRef<BaseTypeNameNode>> m_trie;

Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp (246874 => 246875)


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp	2019-06-27 08:14:30 UTC (rev 246874)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp	2019-06-27 08:19:54 UTC (rev 246875)
@@ -183,7 +183,7 @@
             return resolveWithOperatorAnderIndexer(origin, *firstArgumentArrayRef, intrinsics);
     } else if (name == "operator.length" && types.size() == 1) {
         auto* firstArgumentReference = types[0].get().visit(WTF::makeVisitor([](UniqueRef<AST::UnnamedType>& unnamedType) -> AST::UnnamedType* {
-            if (is<AST::ArrayReferenceType>(static_cast<AST::UnnamedType&>(unnamedType)))
+            if (is<AST::ArrayReferenceType>(static_cast<AST::UnnamedType&>(unnamedType)) || is<AST::ArrayType>(static_cast<AST::UnnamedType&>(unnamedType)))
                 return &unnamedType;
             return nullptr;
         }, [](RefPtr<ResolvableTypeReference>&) -> AST::UnnamedType* {
@@ -1132,9 +1132,7 @@
     ASSERT(variableReference.variable());
     ASSERT(variableReference.variable()->type());
     
-    AST::TypeAnnotation typeAnnotation = AST::RightValue();
-    typeAnnotation = AST::LeftValue { AST::AddressSpace::Thread };
-    assignType(variableReference, variableReference.variable()->type()->clone(), WTFMove(typeAnnotation));
+    assignType(variableReference, variableReference.variable()->type()->clone(), AST::LeftValue { AST::AddressSpace::Thread });
 }
 
 void Checker::visit(AST::Return& returnStatement)

Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp (246874 => 246875)


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp	2019-06-27 08:14:30 UTC (rev 246874)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp	2019-06-27 08:19:54 UTC (rev 246875)
@@ -55,17 +55,17 @@
 class EscapedVariableCollector : public Visitor {
     using Base = Visitor;
 public:
-    void visit(AST::MakePointerExpression& makePointerExpression) override
+
+    void escapeVariableUse(AST::_expression_& _expression_)
     {
-        if (!is<AST::VariableReference>(makePointerExpression.leftValue())) {
+        if (!is<AST::VariableReference>(_expression_)) {
             // FIXME: Are we missing any interesting productions here?
             // https://bugs.webkit.org/show_bug.cgi?id=198311
-            Base::visit(makePointerExpression.leftValue());
+            Base::visit(_expression_);
             return;
         }
 
-        auto& variableReference = downcast<AST::VariableReference>(makePointerExpression.leftValue());
-        auto* variable = variableReference.variable();
+        auto* variable = downcast<AST::VariableReference>(_expression_).variable();
         ASSERT(variable);
         // FIXME: We could skip this if we mark all internal variables with a bit, since we
         // never make any internal variable escape the current scope it is defined in:
@@ -73,6 +73,16 @@
         m_escapedVariables.add(variable, makeString("_", variable->name(), "_", m_count++));
     }
 
+    void visit(AST::MakePointerExpression& makePointerExpression) override
+    {
+        escapeVariableUse(makePointerExpression.leftValue());
+    }
+
+    void visit(AST::MakeArrayReferenceExpression& makeArrayReferenceExpression) override
+    {
+        escapeVariableUse(makeArrayReferenceExpression.leftValue());
+    }
+
     HashMap<AST::VariableDeclaration*, String> takeEscapedVariables() { return WTFMove(m_escapedVariables); }
 
 private:

Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp (246874 => 246875)


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp	2019-06-27 08:14:30 UTC (rev 246874)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp	2019-06-27 08:19:54 UTC (rev 246875)
@@ -95,13 +95,12 @@
 };
 
 template <typename ExpressionConstructor, typename TypeConstructor>
-static Optional<AnderCallArgumentResult> wrapAnderCallArgument(UniqueRef<AST::_expression_>& _expression_, bool anderFunction, bool threadAnderFunction)
+static Optional<AnderCallArgumentResult> wrapAnderCallArgument(UniqueRef<AST::_expression_>& _expression_, UniqueRef<AST::UnnamedType> baseType, bool anderFunction, bool threadAnderFunction)
 {
     if (auto addressSpace = _expression_->typeAnnotation().leftAddressSpace()) {
         if (!anderFunction)
             return WTF::nullopt;
         auto origin = _expression_->origin();
-        auto baseType = _expression_->resolvedType().clone();
         auto makeArrayReference = makeUniqueRef<ExpressionConstructor>(Lexer::Token(origin), WTFMove(_expression_));
         makeArrayReference->setType(makeUniqueRef<TypeConstructor>(WTFMove(origin), *addressSpace, WTFMove(baseType)));
         makeArrayReference->setTypeAnnotation(AST::RightValue());
@@ -109,7 +108,6 @@
     }
     if (threadAnderFunction) {
         auto origin = _expression_->origin();
-        auto baseType = _expression_->resolvedType().clone();
         auto variableDeclaration = makeUniqueRef<AST::VariableDeclaration>(Lexer::Token(origin), AST::Qualifiers(), baseType->clone(), String(), WTF::nullopt, WTF::nullopt);
 
         auto variableReference1 = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variableDeclaration));
@@ -151,9 +149,9 @@
         if (is<AST::ArrayReferenceType>(unnamedType))
             return {{ WTFMove(_expression_), WTF::nullopt, WhichAnder::Ander }};
         if (is<AST::ArrayType>(unnamedType))
-            return wrapAnderCallArgument<AST::MakeArrayReferenceExpression, AST::ArrayReferenceType>(_expression_, anderFunction, threadAnderFunction);
+            return wrapAnderCallArgument<AST::MakeArrayReferenceExpression, AST::ArrayReferenceType>(_expression_, downcast<AST::ArrayType>(unnamedType).type().clone(), anderFunction, threadAnderFunction);
     }
-    return wrapAnderCallArgument<AST::MakePointerExpression, AST::PointerType>(_expression_, anderFunction, threadAnderFunction);
+    return wrapAnderCallArgument<AST::MakePointerExpression, AST::PointerType>(_expression_, _expression_->resolvedType().clone(), anderFunction, threadAnderFunction);
 }
 
 static Optional<UniqueRef<AST::_expression_>> setterCall(AST::PropertyAccessExpression& propertyAccessExpression, AST::FunctionDeclaration* relevantAnder, UniqueRef<AST::_expression_>&& newValue, const std::function<UniqueRef<AST::_expression_>()>& leftValueFactory, AST::VariableDeclaration* indexVariable)

Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt (246874 => 246875)


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt	2019-06-27 08:14:30 UTC (rev 246874)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt	2019-06-27 08:19:54 UTC (rev 246875)
@@ -792,6 +792,12 @@
 int operator--(int value) {
     return value - 1;
 }
+uint operator++(uint value) {
+    return value + 1;
+}
+uint operator--(uint value) {
+    return value - 1;
+}
 
 native ushort Sample(Texture1D<ushort>, sampler, float location);
 native ushort Sample(Texture1DArray<ushort>, sampler, float2 location);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to