Title: [246579] trunk
Revision
246579
Author
sbar...@apple.com
Date
2019-06-18 19:36:42 -0700 (Tue, 18 Jun 2019)

Log Message

[WHLSL] Support matrices
https://bugs.webkit.org/show_bug.cgi?id=198876
<rdar://problem/51768882>

Reviewed by Dean Jackson and Myles Maxfield.

Source/WebCore:

This patch adds in support for matrices to WHLSL. Most matrix related code
is defined by the standard library. This patch just needed to add support
for the native functions operator[] and operator[]= on matrix types. The only
native functions that are named operator[] and operator[]= are for matrix
operations, so we strongly assume when generating code for native operator[] and
operator[]= that we're dealing with matrix types.

operator[]= ignores the write if the index is out of bounds. operator[]
returns a zeroed vector if the index is out of bounds.

This patch also incorporates two bug fixes:
1. This patch takes Robin's patch in https://bugs.webkit.org/show_bug.cgi?id=198313 to ensure
we don't have pointers to values in a hash map. This was needed in this patch
otherwise we'd crash parsing the standard library.

2. This patch fixes how we handle "break" in metal codegen. When I first
implemented break, I strongly assumed we were in a loop. However, break
can be either from a loop or from switch. This patch teaches the metal code
generator to track which context we're in and to emit code accordingly.

Tests: webgpu/whlsl-matrix-2.html
       webgpu/whlsl-matrix.html

* Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop):
* Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp:
(WebCore::WHLSL::Metal::generateMetalCodeShared):
* Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp:
(WebCore::WHLSL::Metal::writeNativeFunction):
* Modules/webgpu/WHLSL/WHLSLChecker.cpp:
(WebCore::WHLSL::Checker::assignTypes):
(WebCore::WHLSL::Checker::getInfo):
(WebCore::WHLSL::Checker::assignType):
(WebCore::WHLSL::Checker::forwardType):
* Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt:

LayoutTests:

* webgpu/whlsl-matrix-2-expected.txt: Added.
* webgpu/whlsl-matrix-2.html: Added.
* webgpu/whlsl-matrix-expected.txt: Added.
* webgpu/whlsl-matrix.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (246578 => 246579)


--- trunk/LayoutTests/ChangeLog	2019-06-19 01:19:41 UTC (rev 246578)
+++ trunk/LayoutTests/ChangeLog	2019-06-19 02:36:42 UTC (rev 246579)
@@ -1,3 +1,16 @@
+2019-06-18  Saam Barati  <sbar...@apple.com>
+
+        [WHLSL] Support matrices
+        https://bugs.webkit.org/show_bug.cgi?id=198876
+        <rdar://problem/51768882>
+
+        Reviewed by Dean Jackson and Myles Maxfield.
+
+        * webgpu/whlsl-matrix-2-expected.txt: Added.
+        * webgpu/whlsl-matrix-2.html: Added.
+        * webgpu/whlsl-matrix-expected.txt: Added.
+        * webgpu/whlsl-matrix.html: Added.
+
 2019-06-18  Russell Epstein  <russel...@apple.com>
 
         Layout Test imported/w3c/web-platform-tests/content-security-policy/reporting/report-only-in-meta.sub.html is failing.

Added: trunk/LayoutTests/webgpu/whlsl-matrix-2-expected.txt (0 => 246579)


--- trunk/LayoutTests/webgpu/whlsl-matrix-2-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-matrix-2-expected.txt	2019-06-19 02:36:42 UTC (rev 246579)
@@ -0,0 +1,12 @@
+PASS successfullyParsed is true
+
+TEST COMPLETE
+PASS resultsFloat32Array[0] is 2
+PASS resultsFloat32Array[1] is 4
+PASS resultsFloat32Array[2] is 6
+PASS resultsFloat32Array[3] is 8
+PASS resultsFloat32Array[4] is 5
+PASS resultsFloat32Array[5] is 6
+PASS resultsFloat32Array[6] is 7
+PASS resultsFloat32Array[7] is 8
+

Added: trunk/LayoutTests/webgpu/whlsl-matrix-2.html (0 => 246579)


--- trunk/LayoutTests/webgpu/whlsl-matrix-2.html	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-matrix-2.html	2019-06-19 02:36:42 UTC (rev 246579)
@@ -0,0 +1,152 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script>
+const shaderSource = `
+bool allEqual(float4x4 mat, float value)
+{
+    for (uint i = 0; i < 4; i = i + 1) {
+        for (uint j = 0; j < 4; j = j + 1) {
+            if (mat[i][j] != value)
+                return false;
+        }
+    }
+    return true;
+}
+
+bool fill(thread float4x4* mat, float value)
+{
+    float4x4 result;
+    for (uint i = 0; i < 4; i = i + 1) {
+            result[i] = float4(value, value, value, value);
+    }
+    *mat = result;
+    return true;
+}
+
+bool fill(thread float4* vec, float value)
+{
+    float4 result;
+    for (uint i = 0; i < 4; i = i + 1) {
+        result[i] = value;
+    }
+    *vec = result;
+    return true;
+}
+
+bool allEqual(float4 vec, float value)
+{
+    for (uint i = 0; i < 4; i = i + 1) {
+        if (vec[i] != value)
+            return false;
+    }
+    return true;
+}
+
+[numthreads(1, 1, 1)]
+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    float4x4 mat;
+    fill(&mat, 1);
+    if (!allEqual(mat, 1))
+        return;
+
+    float4 vec;
+    fill(&vec, 1);
+    if (!allEqual(vec, 1))
+        return;
+
+    float4 vec2 = mul(mat, vec);
+    if (!allEqual(vec2, 4))
+        return;
+
+    float4x4 mat2 = mul(mat, mat);
+    if (!allEqual(mat2, 4))
+        return;
+
+    mat2 = mul(mat2, mat2);
+    if (!allEqual(mat2, 64))
+        return;
+
+    buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0;
+}
+`;
+let resultsFloat32Array;
+async function start() {
+    const adapter = await navigator.gpu.requestAdapter();
+    const device = await adapter.requestDevice();
+
+    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 = Float32Array.BYTES_PER_ELEMENT * 8;
+
+    const bufferDescriptor = {size, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC};
+    const buffer = device.createBuffer(bufferDescriptor);
+    const bufferArrayBuffer = await buffer.mapWriteAsync();
+    const bufferFloat32Array = new Float32Array(bufferArrayBuffer);
+    bufferFloat32Array[0] = 1;
+    bufferFloat32Array[1] = 2;
+    bufferFloat32Array[2] = 3;
+    bufferFloat32Array[3] = 4;
+    bufferFloat32Array[4] = 5;
+    bufferFloat32Array[5] = 6;
+    bufferFloat32Array[6] = 7;
+    bufferFloat32Array[7] = 8;
+    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(4, 1, 1);
+    computePassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+
+    const resultsArrayBuffer = await resultsBuffer.mapReadAsync();
+    resultsFloat32Array = new Float32Array(resultsArrayBuffer);
+    shouldBe("resultsFloat32Array[0]", "2");
+    shouldBe("resultsFloat32Array[1]", "4");
+    shouldBe("resultsFloat32Array[2]", "6");
+    shouldBe("resultsFloat32Array[3]", "8");
+    shouldBe("resultsFloat32Array[4]", "5");
+    shouldBe("resultsFloat32Array[5]", "6");
+    shouldBe("resultsFloat32Array[6]", "7");
+    shouldBe("resultsFloat32Array[7]", "8");
+    resultsBuffer.unmap();
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+window.addEventListener("load", function() {
+    start().then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+});
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/webgpu/whlsl-matrix-expected.txt (0 => 246579)


--- trunk/LayoutTests/webgpu/whlsl-matrix-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-matrix-expected.txt	2019-06-19 02:36:42 UTC (rev 246579)
@@ -0,0 +1,12 @@
+PASS successfullyParsed is true
+
+TEST COMPLETE
+PASS resultsFloat32Array[0] is 2
+PASS resultsFloat32Array[1] is 4
+PASS resultsFloat32Array[2] is 6
+PASS resultsFloat32Array[3] is 8
+PASS resultsFloat32Array[4] is 5
+PASS resultsFloat32Array[5] is 6
+PASS resultsFloat32Array[6] is 7
+PASS resultsFloat32Array[7] is 8
+

Added: trunk/LayoutTests/webgpu/whlsl-matrix.html (0 => 246579)


--- trunk/LayoutTests/webgpu/whlsl-matrix.html	                        (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-matrix.html	2019-06-19 02:36:42 UTC (rev 246579)
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script>
+const shaderSource = `
+bool allEqual(float2x3 mat, float value)
+{
+    for (uint i = 0; i < 2; i = i + 1) {
+        for (uint j = 0; j < 3; j = j + 1) {
+            if (mat[i][j] != value)
+                return false;
+        }
+    }
+    return true;
+}
+
+[numthreads(1, 1, 1)]
+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    float2x3 foo;
+    if (!allEqual(foo, 0))
+        return;
+
+    foo = foo + 1.0;
+    if (!allEqual(foo, 1))
+        return;
+
+    foo = foo * 8.5;
+    if (!allEqual(foo, 8.5))
+        return;
+
+    foo = foo - 7.5;
+    if (!allEqual(foo, 1))
+        return;
+
+    foo = foo + 1.0;
+    if (!allEqual(foo, 2))
+        return;
+
+    foo = foo + foo;
+    if (!allEqual(foo, 4))
+        return;
+
+    foo = foo + foo;
+    if (!allEqual(foo, 8))
+        return;
+
+    float3 fourtyTwo;
+    fourtyTwo.x = 42;
+    fourtyTwo.y = 42;
+    fourtyTwo.z = 42;
+
+    foo[0] = fourtyTwo;
+    foo[1] = fourtyTwo;
+    if (!allEqual(foo, 42))
+        return;
+
+    foo[1337] = fourtyTwo;
+    if (!allEqual(foo, 42))
+        return;
+
+    foo[1000000] = fourtyTwo;
+    if (!allEqual(foo, 42))
+        return;
+
+    fourtyTwo[1337] = 50;
+    foo[1] = fourtyTwo;
+    if (!allEqual(foo, 42))
+        return;
+
+    fourtyTwo[1000000] = 50;
+    foo[1] = fourtyTwo;
+    if (!allEqual(foo, 42))
+        return;
+
+    float3 shouldBeZero = foo[100000];
+    if (shouldBeZero.x != 0 || shouldBeZero.y != 0 || shouldBeZero.z != 0)
+        return;
+
+    if (fourtyTwo[10000000] != 0)
+        return;
+
+    buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0;
+}
+`;
+let resultsFloat32Array;
+async function start() {
+    const adapter = await navigator.gpu.requestAdapter();
+    const device = await adapter.requestDevice();
+
+    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 = Float32Array.BYTES_PER_ELEMENT * 8;
+
+    const bufferDescriptor = {size, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC};
+    const buffer = device.createBuffer(bufferDescriptor);
+    const bufferArrayBuffer = await buffer.mapWriteAsync();
+    const bufferFloat32Array = new Float32Array(bufferArrayBuffer);
+    bufferFloat32Array[0] = 1;
+    bufferFloat32Array[1] = 2;
+    bufferFloat32Array[2] = 3;
+    bufferFloat32Array[3] = 4;
+    bufferFloat32Array[4] = 5;
+    bufferFloat32Array[5] = 6;
+    bufferFloat32Array[6] = 7;
+    bufferFloat32Array[7] = 8;
+    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(4, 1, 1);
+    computePassEncoder.endPass();
+    const commandBuffer = commandEncoder.finish();
+    device.getQueue().submit([commandBuffer]);
+
+    const resultsArrayBuffer = await resultsBuffer.mapReadAsync();
+    resultsFloat32Array = new Float32Array(resultsArrayBuffer);
+    shouldBe("resultsFloat32Array[0]", "2");
+    shouldBe("resultsFloat32Array[1]", "4");
+    shouldBe("resultsFloat32Array[2]", "6");
+    shouldBe("resultsFloat32Array[3]", "8");
+    shouldBe("resultsFloat32Array[4]", "5");
+    shouldBe("resultsFloat32Array[5]", "6");
+    shouldBe("resultsFloat32Array[6]", "7");
+    shouldBe("resultsFloat32Array[7]", "8");
+    resultsBuffer.unmap();
+}
+if (window.testRunner)
+    testRunner.waitUntilDone();
+window.addEventListener("load", function() {
+    start().then(function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }, function() {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    });
+});
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (246578 => 246579)


--- trunk/Source/WebCore/ChangeLog	2019-06-19 01:19:41 UTC (rev 246578)
+++ trunk/Source/WebCore/ChangeLog	2019-06-19 02:36:42 UTC (rev 246579)
@@ -1,3 +1,48 @@
+2019-06-18  Saam Barati  <sbar...@apple.com>
+
+        [WHLSL] Support matrices
+        https://bugs.webkit.org/show_bug.cgi?id=198876
+        <rdar://problem/51768882>
+
+        Reviewed by Dean Jackson and Myles Maxfield.
+
+        This patch adds in support for matrices to WHLSL. Most matrix related code
+        is defined by the standard library. This patch just needed to add support
+        for the native functions operator[] and operator[]= on matrix types. The only
+        native functions that are named operator[] and operator[]= are for matrix
+        operations, so we strongly assume when generating code for native operator[] and
+        operator[]= that we're dealing with matrix types.
+        
+        operator[]= ignores the write if the index is out of bounds. operator[]
+        returns a zeroed vector if the index is out of bounds.  
+        
+        This patch also incorporates two bug fixes:
+        1. This patch takes Robin's patch in https://bugs.webkit.org/show_bug.cgi?id=198313 to ensure
+        we don't have pointers to values in a hash map. This was needed in this patch
+        otherwise we'd crash parsing the standard library.
+        
+        2. This patch fixes how we handle "break" in metal codegen. When I first
+        implemented break, I strongly assumed we were in a loop. However, break
+        can be either from a loop or from switch. This patch teaches the metal code
+        generator to track which context we're in and to emit code accordingly.
+
+        Tests: webgpu/whlsl-matrix-2.html
+               webgpu/whlsl-matrix.html
+
+        * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop):
+        * Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp:
+        (WebCore::WHLSL::Metal::generateMetalCodeShared):
+        * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp:
+        (WebCore::WHLSL::Metal::writeNativeFunction):
+        * Modules/webgpu/WHLSL/WHLSLChecker.cpp:
+        (WebCore::WHLSL::Checker::assignTypes):
+        (WebCore::WHLSL::Checker::getInfo):
+        (WebCore::WHLSL::Checker::assignType):
+        (WebCore::WHLSL::Checker::forwardType):
+        * Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt:
+
 2019-06-18  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] JSLock should be WebThread aware

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


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp	2019-06-19 01:19:41 UTC (rev 246578)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp	2019-06-19 02:36:42 UTC (rev 246579)
@@ -191,6 +191,13 @@
         return m_stack.takeLast().leftValue;
     }
 
+    enum class BreakContext {
+        Loop,
+        Switch
+    };
+
+    Optional<BreakContext> m_currentBreakContext;
+
     Intrinsics& m_intrinsics;
     TypeNamer& m_typeNamer;
     HashMap<AST::FunctionDeclaration*, String>& m_functionMapping;
@@ -271,9 +278,17 @@
 
 void FunctionDefinitionWriter::visit(AST::Break&)
 {
-    ASSERT(m_breakOutOfCurrentLoopEarlyVariable.length());
-    m_stringBuilder.append(makeString(m_breakOutOfCurrentLoopEarlyVariable, " = true;\n"));
-    m_stringBuilder.append("break;\n");
+    ASSERT(m_currentBreakContext);
+    switch (*m_currentBreakContext) {
+    case BreakContext::Switch:
+        m_stringBuilder.append("break;\n");
+        break;
+    case BreakContext::Loop:
+        ASSERT(m_breakOutOfCurrentLoopEarlyVariable.length());
+        m_stringBuilder.append(makeString(m_breakOutOfCurrentLoopEarlyVariable, " = true;\n"));
+        m_stringBuilder.append("break;\n");
+        break;
+    }
 }
 
 void FunctionDefinitionWriter::visit(AST::Continue&)
@@ -307,6 +322,7 @@
     }
 
     m_stringBuilder.append("do {\n");
+    SetForScope<Optional<BreakContext>> breakContext(m_currentBreakContext, BreakContext::Loop);
     checkErrorAndVisit(body);
     m_stringBuilder.append("} while(false); \n");
     m_stringBuilder.append(makeString("if (", m_breakOutOfCurrentLoopEarlyVariable, ") break;\n"));
@@ -393,9 +409,9 @@
         m_stringBuilder.append(makeString("case ", constantExpressionString(*switchCase.value()), ":\n"));
     else
         m_stringBuilder.append("default:\n");
+    SetForScope<Optional<BreakContext>> breakContext(m_currentBreakContext, BreakContext::Switch);
     checkErrorAndVisit(switchCase.block());
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195812 Figure out whether we need to break or fallthrough.
-    notImplemented();
 }
 
 void FunctionDefinitionWriter::visit(AST::Trap&)

Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp (246578 => 246579)


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp	2019-06-19 01:19:41 UTC (rev 246578)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp	2019-06-19 02:36:42 UTC (rev 246579)
@@ -30,6 +30,7 @@
 
 #include "WHLSLFunctionWriter.h"
 #include "WHLSLTypeNamer.h"
+#include <wtf/DataLog.h>
 #include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
@@ -38,6 +39,8 @@
 
 namespace Metal {
 
+static constexpr bool dumpMetalCode = false;
+
 static String generateMetalCodeShared(String&& metalTypes, String&& metalFunctions)
 {
     StringBuilder stringBuilder;
@@ -53,6 +56,12 @@
 
     stringBuilder.append(WTFMove(metalTypes));
     stringBuilder.append(WTFMove(metalFunctions));
+
+    if (dumpMetalCode) {
+        dataLogLn("Generated Metal code: ");
+        dataLogLn(stringBuilder.toString());
+    }
+
     return stringBuilder.toString();
 }
 

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


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp	2019-06-19 01:19:41 UTC (rev 246578)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp	2019-06-19 02:36:42 UTC (rev 246579)
@@ -225,6 +225,39 @@
         return stringBuilder.toString();
     }
 
+    auto numberOfMatrixRows = [&] {
+        auto& typeReference = downcast<AST::TypeReference>(*nativeFunctionDeclaration.parameters()[0]->type());
+        auto& matrixType = downcast<AST::NativeTypeDeclaration>(downcast<AST::TypeReference>(downcast<AST::TypeDefinition>(typeReference.resolvedType()).type()).resolvedType());
+        ASSERT(matrixType.name() == "matrix");
+        ASSERT(matrixType.typeArguments().size() == 3);
+        return String::number(WTF::get<AST::ConstantExpression>(matrixType.typeArguments()[1]).integerLiteral().value());
+    };
+
+    if (nativeFunctionDeclaration.name() == "operator[]") {
+        ASSERT(nativeFunctionDeclaration.parameters().size() == 2);
+        auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
+        auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
+        auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
+        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i) {\n"));
+        stringBuilder.append(makeString("    if (i < ", numberOfMatrixRows(), ") return m[i];\n"));
+        stringBuilder.append(makeString("    return ", metalReturnName, "(0);\n"));
+        stringBuilder.append("}\n");
+        return stringBuilder.toString();
+    }
+
+    if (nativeFunctionDeclaration.name() == "operator[]=") {
+        ASSERT(nativeFunctionDeclaration.parameters().size() == 3);
+        auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
+        auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
+        auto metalParameter3Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[2]->type());
+        auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
+        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i, ", metalParameter3Name, " v) {\n"));
+        stringBuilder.append(makeString("    if (i < ", numberOfMatrixRows(), ") m[i] = v;\n"));
+        stringBuilder.append("    return m;\n");
+        stringBuilder.append("}\n");
+        return stringBuilder.toString();
+    }
+
     if (nativeFunctionDeclaration.isOperator()) {
         if (nativeFunctionDeclaration.parameters().size() == 1) {
             auto operatorName = nativeFunctionDeclaration.name().substring("operator"_str.length());

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


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp	2019-06-19 01:19:41 UTC (rev 246578)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp	2019-06-19 02:36:42 UTC (rev 246579)
@@ -507,7 +507,7 @@
 
     void finishVisiting(AST::PropertyAccessExpression&, ResolvingType* additionalArgumentType = nullptr);
 
-    HashMap<AST::_expression_*, ResolvingType> m_typeMap;
+    HashMap<AST::_expression_*, std::unique_ptr<ResolvingType>> m_typeMap;
     HashMap<AST::_expression_*, AST::TypeAnnotation> m_typeAnnotations;
     HashSet<String> m_vertexEntryPoints;
     HashSet<String> m_fragmentEntryPoints;
@@ -537,7 +537,7 @@
 bool Checker::assignTypes()
 {
     for (auto& keyValuePair : m_typeMap) {
-        auto success = keyValuePair.value.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& unnamedType) -> bool {
+        auto success = keyValuePair.value->visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& unnamedType) -> bool {
             keyValuePair.key->setType(unnamedType->clone());
             return true;
         }, [&](RefPtr<ResolvableTypeReference>& resolvableTypeReference) -> bool {
@@ -780,7 +780,7 @@
         setError();
         return WTF::nullopt;
     }
-    return {{ typeIterator->value, typeAnnotationIterator->value }};
+    return {{ *typeIterator->value, typeAnnotationIterator->value }};
 }
 
 void Checker::visit(AST::VariableDeclaration& variableDeclaration)
@@ -802,7 +802,7 @@
 
 void Checker::assignType(AST::_expression_& _expression_, UniqueRef<AST::UnnamedType>&& unnamedType, AST::TypeAnnotation typeAnnotation = AST::RightValue())
 {
-    auto addResult = m_typeMap.add(&_expression_, WTFMove(unnamedType));
+    auto addResult = m_typeMap.add(&_expression_, std::make_unique<ResolvingType>(WTFMove(unnamedType)));
     ASSERT_UNUSED(addResult, addResult.isNewEntry);
     auto typeAnnotationAddResult = m_typeAnnotations.add(&_expression_, WTFMove(typeAnnotation));
     ASSERT_UNUSED(typeAnnotationAddResult, typeAnnotationAddResult.isNewEntry);
@@ -810,7 +810,7 @@
 
 void Checker::assignType(AST::_expression_& _expression_, RefPtr<ResolvableTypeReference>&& resolvableTypeReference, AST::TypeAnnotation typeAnnotation = AST::RightValue())
 {
-    auto addResult = m_typeMap.add(&_expression_, WTFMove(resolvableTypeReference));
+    auto addResult = m_typeMap.add(&_expression_, std::make_unique<ResolvingType>(WTFMove(resolvableTypeReference)));
     ASSERT_UNUSED(addResult, addResult.isNewEntry);
     auto typeAnnotationAddResult = m_typeAnnotations.add(&_expression_, WTFMove(typeAnnotation));
     ASSERT_UNUSED(typeAnnotationAddResult, typeAnnotationAddResult.isNewEntry);
@@ -819,10 +819,10 @@
 void Checker::forwardType(AST::_expression_& _expression_, ResolvingType& resolvingType, AST::TypeAnnotation typeAnnotation = AST::RightValue())
 {
     resolvingType.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& result) {
-        auto addResult = m_typeMap.add(&_expression_, result->clone());
+        auto addResult = m_typeMap.add(&_expression_, std::make_unique<ResolvingType>(result->clone()));
         ASSERT_UNUSED(addResult, addResult.isNewEntry);
     }, [&](RefPtr<ResolvableTypeReference>& result) {
-        auto addResult = m_typeMap.add(&_expression_, result.copyRef());
+        auto addResult = m_typeMap.add(&_expression_, std::make_unique<ResolvingType>(result.copyRef()));
         ASSERT_UNUSED(addResult, addResult.isNewEntry);
     }));
     auto typeAnnotationAddResult = m_typeAnnotations.add(&_expression_, WTFMove(typeAnnotation));

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


--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt	2019-06-19 01:19:41 UTC (rev 246578)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt	2019-06-19 02:36:42 UTC (rev 246579)
@@ -625,4 +625,227 @@
     return result;
 }
 
+native float3 operator[](float2x3, uint);
+native float2x3 operator[]=(float2x3, uint, float3);
+float operator[](float3 v, uint index) {
+    switch (index) {
+        case 0:
+            return v.x;
+        case 1:
+            return v.y;
+        case 2:
+            return v.z;
+        default:
+            break;
+    }
+    return 0.0;
+}
+float3 operator[]=(float3 v, uint index, float a) {
+    switch (index) {
+        case 0:
+            v.x = a;
+            break;
+        case 1:
+            v.y = a;
+            break;
+        case 2:
+            v.z = a;
+            break;
+        default:
+            break;
+    }
+    return v;
+}
+float2x3 operator+(float2x3 a, float2x3 b) {
+    float2x3 result;
+    result[0][0] = a[0][0] + b[0][0];
+    result[0][1] = a[0][1] + b[0][1];
+    result[0][2] = a[0][2] + b[0][2];
+    result[1][0] = a[1][0] + b[1][0];
+    result[1][1] = a[1][1] + b[1][1];
+    result[1][2] = a[1][2] + b[1][2];
+    return result;
+}
+float2x3 operator*(float2x3 a, float b) {
+    float2x3 result;
+    result[0][0] = a[0][0] * b;
+    result[0][1] = a[0][1] * b;
+    result[0][2] = a[0][2] * b;
+    result[1][0] = a[1][0] * b;
+    result[1][1] = a[1][1] * b;
+    result[1][2] = a[1][2] * b;
+    return result;
+}
+float2x3 operator+(float2x3 a, float b) {
+    float2x3 result;
+    result[0][0] = a[0][0] + b;
+    result[0][1] = a[0][1] + b;
+    result[0][2] = a[0][2] + b;
+    result[1][0] = a[1][0] + b;
+    result[1][1] = a[1][1] + b;
+    result[1][2] = a[1][2] + b;
+    return result;
+}
+float2x3 operator-(float2x3 a, float b) {
+    float2x3 result;
+    result[0][0] = a[0][0] - b;
+    result[0][1] = a[0][1] - b;
+    result[0][2] = a[0][2] - b;
+    result[1][0] = a[1][0] - b;
+    result[1][1] = a[1][1] - b;
+    result[1][2] = a[1][2] - b;
+    return result;
+}
+
+typedef float4x4 = matrix<float, 4, 4>;
+native float4 operator[](float4x4, uint);
+native float4x4 operator[]=(float4x4, uint, float4);
+
+float operator[](float4 v, uint index) {
+    switch (index) {
+        case 0:
+            return v.x;
+        case 1:
+            return v.y;
+        case 2:
+            return v.z;
+        case 3:
+            return v.w;
+        default:
+            break;
+    }
+    float result;
+    return result;
+}
+
+float4 operator[]=(float4 v, uint index, float a) {
+    switch (index) {
+        case 0:
+            v.x = a;
+            break;
+        case 1:
+            v.y = a;
+            break;
+        case 2:
+            v.z = a;
+            break;
+        case 3:
+            v.w = a;
+            break;
+        default:
+            break;
+    }
+    return v;
+}
+
+float4 mul(float4x4 x, float4 y) {
+    float4 result;
+    result[0] = 0;
+    result[0] = result[0] + x[0][0] * y[0];
+    result[0] = result[0] + x[0][1] * y[1];
+    result[0] = result[0] + x[0][2] * y[2];
+    result[0] = result[0] + x[0][3] * y[3];
+    result[1] = 0;
+    result[1] = result[1] + x[1][0] * y[0];
+    result[1] = result[1] + x[1][1] * y[1];
+    result[1] = result[1] + x[1][2] * y[2];
+    result[1] = result[1] + x[1][3] * y[3];
+    result[2] = 0;
+    result[2] = result[2] + x[2][0] * y[0];
+    result[2] = result[2] + x[2][1] * y[1];
+    result[2] = result[2] + x[2][2] * y[2];
+    result[2] = result[2] + x[2][3] * y[3];
+    result[3] = 0;
+    result[3] = result[3] + x[3][0] * y[0];
+    result[3] = result[3] + x[3][1] * y[1];
+    result[3] = result[3] + x[3][2] * y[2];
+    result[3] = result[3] + x[3][3] * y[3];
+    return result;
+}
+
+float4x4 mul(float4x4 x, float4x4 y) {
+    float4x4 result;
+    result[0][0] = 0;
+    result[0][0] = result[0][0] + x[0][0] * y[0][0];
+    result[0][0] = result[0][0] + x[0][1] * y[1][0];
+    result[0][0] = result[0][0] + x[0][2] * y[2][0];
+    result[0][0] = result[0][0] + x[0][3] * y[3][0];
+    result[0][1] = 0;
+    result[0][1] = result[0][1] + x[0][0] * y[0][1];
+    result[0][1] = result[0][1] + x[0][1] * y[1][1];
+    result[0][1] = result[0][1] + x[0][2] * y[2][1];
+    result[0][1] = result[0][1] + x[0][3] * y[3][1];
+    result[0][2] = 0;
+    result[0][2] = result[0][2] + x[0][0] * y[0][2];
+    result[0][2] = result[0][2] + x[0][1] * y[1][2];
+    result[0][2] = result[0][2] + x[0][2] * y[2][2];
+    result[0][2] = result[0][2] + x[0][3] * y[3][2];
+    result[0][3] = 0;
+    result[0][3] = result[0][3] + x[0][0] * y[0][3];
+    result[0][3] = result[0][3] + x[0][1] * y[1][3];
+    result[0][3] = result[0][3] + x[0][2] * y[2][3];
+    result[0][3] = result[0][3] + x[0][3] * y[3][3];
+    result[1][0] = 0;
+    result[1][0] = result[1][0] + x[1][0] * y[0][0];
+    result[1][0] = result[1][0] + x[1][1] * y[1][0];
+    result[1][0] = result[1][0] + x[1][2] * y[2][0];
+    result[1][0] = result[1][0] + x[1][3] * y[3][0];
+    result[1][1] = 0;
+    result[1][1] = result[1][1] + x[1][0] * y[0][1];
+    result[1][1] = result[1][1] + x[1][1] * y[1][1];
+    result[1][1] = result[1][1] + x[1][2] * y[2][1];
+    result[1][1] = result[1][1] + x[1][3] * y[3][1];
+    result[1][2] = 0;
+    result[1][2] = result[1][2] + x[1][0] * y[0][2];
+    result[1][2] = result[1][2] + x[1][1] * y[1][2];
+    result[1][2] = result[1][2] + x[1][2] * y[2][2];
+    result[1][2] = result[1][2] + x[1][3] * y[3][2];
+    result[1][3] = 0;
+    result[1][3] = result[1][3] + x[1][0] * y[0][3];
+    result[1][3] = result[1][3] + x[1][1] * y[1][3];
+    result[1][3] = result[1][3] + x[1][2] * y[2][3];
+    result[1][3] = result[1][3] + x[1][3] * y[3][3];
+    result[2][0] = 0;
+    result[2][0] = result[2][0] + x[2][0] * y[0][0];
+    result[2][0] = result[2][0] + x[2][1] * y[1][0];
+    result[2][0] = result[2][0] + x[2][2] * y[2][0];
+    result[2][0] = result[2][0] + x[2][3] * y[3][0];
+    result[2][1] = 0;
+    result[2][1] = result[2][1] + x[2][0] * y[0][1];
+    result[2][1] = result[2][1] + x[2][1] * y[1][1];
+    result[2][1] = result[2][1] + x[2][2] * y[2][1];
+    result[2][1] = result[2][1] + x[2][3] * y[3][1];
+    result[2][2] = 0;
+    result[2][2] = result[2][2] + x[2][0] * y[0][2];
+    result[2][2] = result[2][2] + x[2][1] * y[1][2];
+    result[2][2] = result[2][2] + x[2][2] * y[2][2];
+    result[2][2] = result[2][2] + x[2][3] * y[3][2];
+    result[2][3] = 0;
+    result[2][3] = result[2][3] + x[2][0] * y[0][3];
+    result[2][3] = result[2][3] + x[2][1] * y[1][3];
+    result[2][3] = result[2][3] + x[2][2] * y[2][3];
+    result[2][3] = result[2][3] + x[2][3] * y[3][3];
+    result[3][0] = 0;
+    result[3][0] = result[3][0] + x[3][0] * y[0][0];
+    result[3][0] = result[3][0] + x[3][1] * y[1][0];
+    result[3][0] = result[3][0] + x[3][2] * y[2][0];
+    result[3][0] = result[3][0] + x[3][3] * y[3][0];
+    result[3][1] = 0;
+    result[3][1] = result[3][1] + x[3][0] * y[0][1];
+    result[3][1] = result[3][1] + x[3][1] * y[1][1];
+    result[3][1] = result[3][1] + x[3][2] * y[2][1];
+    result[3][1] = result[3][1] + x[3][3] * y[3][1];
+    result[3][2] = 0;
+    result[3][2] = result[3][2] + x[3][0] * y[0][2];
+    result[3][2] = result[3][2] + x[3][1] * y[1][2];
+    result[3][2] = result[3][2] + x[3][2] * y[2][2];
+    result[3][2] = result[3][2] + x[3][3] * y[3][2];
+    result[3][3] = 0;
+    result[3][3] = result[3][3] + x[3][0] * y[0][3];
+    result[3][3] = result[3][3] + x[3][1] * y[1][3];
+    result[3][3] = result[3][3] + x[3][2] * y[2][3];
+    result[3][3] = result[3][3] + x[3][3] * y[3][3];
+    return result;
+}
+
 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=192890 Insert the rest of the standard library once the parser is fast enough
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to