[WHLSL] Implement out-of-bounds and nullptr behavior
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 14 Jun 2019 18:01:05 +0000 (18:01 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 14 Jun 2019 18:01:05 +0000 (18:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=198600
<rdar://problem/51668853>

Reviewed by Robin Morisset.

Source/WebCore:

The behavior we're implementing is:
- OOB writes are ignored.
- OOB reads return zero.
- Writes to null are ignored.
- Reads from null return zero.
- &*x == x, including &*null == null.

We implement this like so:
- The value stack in FunctionWriter turns into a stack of pairs: rvalues and lvalues.
  rvalues are represented the same as before. Lvalues are always pointers.
- Anything that produces an lvalue must push a pointer to the stack. Not
  all things produce lvalues, so that entry in the stack may be empty.
  However, all things that produce lvalues also produce rvalues. So, "*x = 42" works,
  and so does "foo(*x)". Nodes that produce lvalues are responsible for also producing
  an rvalue, which should be the value as if the lvalue was dereferenced at that point
  in program execution. So the "*x" in "thread int* x = null; *x" produces the int zero
  for its rvalue, and null for its lvalue.
- Dereference just works, as dereference produces both an lvalue and rvalue. Dereference
  node's child must also be an lvalue. So we just forward that value along on
  the stack. For the rvalue, if we try to dereference nullptr, we just fill in
  zero bytes instead. Otherwise, the rvalue is the result of dereferencing the
  non-null pointer.
- Assignment expressions check if the incoming lvalue is null. If it is, it
  skips the assignment.
- operator&[] returns nullptr on an OOB access. Then, based on the above
  behavior, we get the desired OOB reads return zero, and OOB writes are
  ignored.
- MakePointerExpression just takes the last lvalue off the stack (which must
  be a pointer) and returns it as an rvalue.
- VariableReference will push both the variable value and a pointer to the variable
  onto the stack.

This patch also fixes a few bugs where we weren't giving certain AST nodes the
proper address space values.

This patch also removes code to generate native functions for operators
"operator[]" and "operator[]=" as we should never be generating these
ourselves. We should only be generating the "operator&[]" ander.

Tests: webgpu/whlsl-null-dereference.html
       webgpu/whlsl-oob-access.html

* Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::FunctionDefinitionWriter):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::appendRightValue):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::appendLeftValue):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::takeLastValue):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::takeLastLeftValue):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop):
* Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp:
(WebCore::WHLSL::Metal::writeNativeFunction):
* Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h:
* Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp:
(WebCore::WHLSL::Metal::TypeNamer::emitUnnamedTypeDefinition):
* Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp:
(WebCore::WHLSL::PreserveLifetimes::assignVariableIntoStruct):
* Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp:
(WebCore::WHLSL::PropertyResolver::visit):
* Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt:
* platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm:
(WebCore::trySetFunctions):
* platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
(WebCore::trySetFunctions):

LayoutTests:

* webgpu/whlsl-null-dereference-expected.txt: Added.
* webgpu/whlsl-null-dereference.html: Added.
* webgpu/whlsl-oob-access-expected.txt: Added.
* webgpu/whlsl-oob-access.html: Added.

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/webgpu/whlsl-null-dereference-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl-null-dereference.html [new file with mode: 0644]
LayoutTests/webgpu/whlsl-oob-access-expected.txt [new file with mode: 0644]
LayoutTests/webgpu/whlsl-oob-access.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h
Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp
Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt
Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm
Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm

index dd38ee0..2a772e8 100644 (file)
@@ -1,3 +1,16 @@
+2019-06-14  Saam Barati  <sbarati@apple.com>
+
+        [WHLSL] Implement out-of-bounds and nullptr behavior
+        https://bugs.webkit.org/show_bug.cgi?id=198600
+        <rdar://problem/51668853>
+
+        Reviewed by Robin Morisset.
+
+        * webgpu/whlsl-null-dereference-expected.txt: Added.
+        * webgpu/whlsl-null-dereference.html: Added.
+        * webgpu/whlsl-oob-access-expected.txt: Added.
+        * webgpu/whlsl-oob-access.html: Added.
+
 2019-06-14  Youenn Fablet  <youenn@apple.com>
 
         Cloning a MediaStreamTrack does not clone the logger
diff --git a/LayoutTests/webgpu/whlsl-null-dereference-expected.txt b/LayoutTests/webgpu/whlsl-null-dereference-expected.txt
new file mode 100644 (file)
index 0000000..6e1668a
--- /dev/null
@@ -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
+
diff --git a/LayoutTests/webgpu/whlsl-null-dereference.html b/LayoutTests/webgpu/whlsl-null-dereference.html
new file mode 100644 (file)
index 0000000..6a81382
--- /dev/null
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const shaderSource = `
+typedef Foo = thread int*;
+Foo getNullPtr()
+{
+    return null;
+}
+
+struct XYZ {
+    float x;
+    float y;
+    float z;
+}
+
+[numthreads(2, 1, 1)]
+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    Foo ptr = null;
+    *ptr = 42;
+    *getNullPtr() = 42;
+    if (*ptr == 0) {
+        if (ptr == getNullPtr()) {
+            if (*getNullPtr() == 0) {
+                thread XYZ* xyzPtr = null;
+                XYZ xyz;
+                xyz.x = 1;
+                xyz.y = 1;
+                xyz.z = 1;
+                if (xyz.z == 1.0 && xyz.y == 1.0 && xyz.z == 1.0) {
+                    *xyzPtr = xyz;
+                    xyz = *xyzPtr;
+                    if (xyz.z == 0.0 && xyz.y == 0.0 && xyz.z == 0.0) {
+                        if (&*getNullPtr() == null) {
+                            if (&*(&*getNullPtr()) == null) {
+                                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 bufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, 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: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ};
+    const resultsBuffer = device.createBuffer(resultsBufferDescriptor);
+
+    const bufferBinding = {buffer: resultsBuffer, size: 4};
+    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, Float32Array.BYTES_PER_ELEMENT * 8);
+    const computePassEncoder = commandEncoder.beginComputePass();
+    computePassEncoder.setPipeline(computePipeline);
+    computePassEncoder.setBindGroup(0, bindGroup);
+    computePassEncoder.dispatch(2, 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="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/webgpu/whlsl-oob-access-expected.txt b/LayoutTests/webgpu/whlsl-oob-access-expected.txt
new file mode 100644 (file)
index 0000000..6e1668a
--- /dev/null
@@ -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
+
diff --git a/LayoutTests/webgpu/whlsl-oob-access.html b/LayoutTests/webgpu/whlsl-oob-access.html
new file mode 100644 (file)
index 0000000..4959cb1
--- /dev/null
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+const shaderSource = `
+[numthreads(2, 1, 1)]
+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) {
+    buffer[1337] = 0.0;
+    buffer[42424242] = 0.0;
+    if (buffer[100000] == 0.0)
+        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 bufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, 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: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ};
+    const resultsBuffer = device.createBuffer(resultsBufferDescriptor);
+
+    const bufferBinding = {buffer: resultsBuffer, size: 4};
+    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, Float32Array.BYTES_PER_ELEMENT * 8);
+    const computePassEncoder = commandEncoder.beginComputePass();
+    computePassEncoder.setPipeline(computePipeline);
+    computePassEncoder.setBindGroup(0, bindGroup);
+    computePassEncoder.dispatch(2, 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="../resources/js-test-post.js"></script>
+</body>
+</html>
index a2c12ef..d1bf8cb 100644 (file)
@@ -1,3 +1,76 @@
+2019-06-14  Saam Barati  <sbarati@apple.com>
+
+        [WHLSL] Implement out-of-bounds and nullptr behavior
+        https://bugs.webkit.org/show_bug.cgi?id=198600
+        <rdar://problem/51668853>
+
+        Reviewed by Robin Morisset.
+
+        The behavior we're implementing is:
+        - OOB writes are ignored.
+        - OOB reads return zero.
+        - Writes to null are ignored.
+        - Reads from null return zero.
+        - &*x == x, including &*null == null.
+        
+        We implement this like so:
+        - The value stack in FunctionWriter turns into a stack of pairs: rvalues and lvalues.
+          rvalues are represented the same as before. Lvalues are always pointers.
+        - Anything that produces an lvalue must push a pointer to the stack. Not
+          all things produce lvalues, so that entry in the stack may be empty.
+          However, all things that produce lvalues also produce rvalues. So, "*x = 42" works,
+          and so does "foo(*x)". Nodes that produce lvalues are responsible for also producing
+          an rvalue, which should be the value as if the lvalue was dereferenced at that point
+          in program execution. So the "*x" in "thread int* x = null; *x" produces the int zero
+          for its rvalue, and null for its lvalue.
+        - Dereference just works, as dereference produces both an lvalue and rvalue. Dereference
+          node's child must also be an lvalue. So we just forward that value along on
+          the stack. For the rvalue, if we try to dereference nullptr, we just fill in
+          zero bytes instead. Otherwise, the rvalue is the result of dereferencing the
+          non-null pointer.
+        - Assignment expressions check if the incoming lvalue is null. If it is, it
+          skips the assignment.
+        - operator&[] returns nullptr on an OOB access. Then, based on the above
+          behavior, we get the desired OOB reads return zero, and OOB writes are
+          ignored.
+        - MakePointerExpression just takes the last lvalue off the stack (which must
+          be a pointer) and returns it as an rvalue.
+        - VariableReference will push both the variable value and a pointer to the variable
+          onto the stack.
+
+        This patch also fixes a few bugs where we weren't giving certain AST nodes the
+        proper address space values.
+
+        This patch also removes code to generate native functions for operators
+        "operator[]" and "operator[]=" as we should never be generating these
+        ourselves. We should only be generating the "operator&[]" ander.
+
+        Tests: webgpu/whlsl-null-dereference.html
+               webgpu/whlsl-oob-access.html
+
+        * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::FunctionDefinitionWriter):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::appendRightValue):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::appendLeftValue):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::takeLastValue):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::takeLastLeftValue):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
+        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop):
+        * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp:
+        (WebCore::WHLSL::Metal::writeNativeFunction):
+        * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h:
+        * Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp:
+        (WebCore::WHLSL::Metal::TypeNamer::emitUnnamedTypeDefinition):
+        * Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp:
+        (WebCore::WHLSL::PreserveLifetimes::assignVariableIntoStruct):
+        * Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp:
+        (WebCore::WHLSL::PropertyResolver::visit):
+        * Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt:
+        * platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm:
+        (WebCore::trySetFunctions):
+        * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
+        (WebCore::trySetFunctions):
+
 2019-06-14  Jer Noble  <jer.noble@apple.com>
 
         CRASH(nullptr) in WebCore::jsAudioContextCurrentTime()
index 009d431..a416001 100644 (file)
@@ -88,8 +88,18 @@ public:
         , m_functionMapping(functionMapping)
         , m_layout(layout)
     {
+        m_stringBuilder.append(makeString(
+            "template <typename T>\n"
+            "inline void ", memsetZeroFunctionName, "(thread T& value)\n"
+            "{\n"
+            "    thread char* ptr = static_cast<thread char*>(static_cast<thread void*>(&value));\n"
+            "    for (size_t i = 0; i < sizeof(T); ++i)\n"
+            "        ptr[i] = 0;\n"
+            "}\n"));
     }
 
+    static constexpr const char* memsetZeroFunctionName = "memsetZero";
+
     virtual ~FunctionDefinitionWriter() = default;
 
     String toString() { return m_stringBuilder.toString(); }
@@ -153,12 +163,41 @@ protected:
         return makeString("variable", m_variableCount++);
     }
 
+    struct StackItem {
+        String value;
+        String leftValue;
+    };
+
+    void appendRightValue(AST::Expression&, String value)
+    {
+        m_stack.append({ WTFMove(value), String() });
+    }
+
+    void appendLeftValue(AST::Expression& expression, String value, String leftValue)
+    {
+        ASSERT_UNUSED(expression, expression.typeAnnotation().leftAddressSpace());
+        m_stack.append({ WTFMove(value), WTFMove(leftValue) });
+    }
+
+    String takeLastValue()
+    {
+        ASSERT(m_stack.last().value);
+        return m_stack.takeLast().value;
+    }
+
+    String takeLastLeftValue()
+    {
+        ASSERT(m_stack.last().leftValue);
+        return m_stack.takeLast().leftValue;
+    }
+
     Intrinsics& m_intrinsics;
     TypeNamer& m_typeNamer;
     HashMap<AST::FunctionDeclaration*, String>& m_functionMapping;
     HashMap<AST::VariableDeclaration*, String> m_variableMapping;
     StringBuilder m_stringBuilder;
-    Vector<String> m_stack;
+
+    Vector<StackItem> m_stack;
     std::unique_ptr<EntryPointScaffolding> m_entryPointScaffolding;
     Layout& m_layout;
     unsigned m_variableCount { 0 };
@@ -169,7 +208,7 @@ void FunctionDefinitionWriter::visit(AST::NativeFunctionDeclaration& nativeFunct
 {
     auto iterator = m_functionMapping.find(&nativeFunctionDeclaration);
     ASSERT(iterator != m_functionMapping.end());
-    m_stringBuilder.append(writeNativeFunction(nativeFunctionDeclaration, iterator->value, m_intrinsics, m_typeNamer));
+    m_stringBuilder.append(writeNativeFunction(nativeFunctionDeclaration, iterator->value, m_intrinsics, m_typeNamer, memsetZeroFunctionName));
 }
 
 void FunctionDefinitionWriter::visit(AST::FunctionDefinition& functionDefinition)
@@ -246,7 +285,7 @@ void FunctionDefinitionWriter::visit(AST::Continue&)
 void FunctionDefinitionWriter::visit(AST::EffectfulExpressionStatement& effectfulExpressionStatement)
 {
     checkErrorAndVisit(effectfulExpressionStatement.effectfulExpression());
-    m_stack.takeLast(); // The statement is already effectful, so we don't need to do anything with the result.
+    takeLastValue(); // The statement is already effectful, so we don't need to do anything with the result.
 }
 
 void FunctionDefinitionWriter::visit(AST::Fallthrough&)
@@ -264,7 +303,7 @@ void FunctionDefinitionWriter::emitLoop(LoopConditionLocation loopConditionLocat
 
     if (loopConditionLocation == LoopConditionLocation::BeforeBody && conditionExpression) {
         checkErrorAndVisit(*conditionExpression);
-        m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n"));
+        m_stringBuilder.append(makeString("if (!", takeLastValue(), ") break;\n"));
     }
 
     m_stringBuilder.append("do {\n");
@@ -276,12 +315,12 @@ void FunctionDefinitionWriter::emitLoop(LoopConditionLocation loopConditionLocat
         checkErrorAndVisit(*increment);
         // Expression results get pushed to m_stack. We don't use the result
         // of increment, so we dispense of that now.
-        m_stack.takeLast();
+        takeLastValue();
     }
 
     if (loopConditionLocation == LoopConditionLocation::AfterBody && conditionExpression) {
         checkErrorAndVisit(*conditionExpression);
-        m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n"));
+        m_stringBuilder.append(makeString("if (!", takeLastValue(), ") break;\n"));
     }
 
     m_stringBuilder.append("} \n");
@@ -305,7 +344,7 @@ void FunctionDefinitionWriter::visit(AST::ForLoop& forLoop)
         checkErrorAndVisit(statement);
     }, [&](UniqueRef<AST::Expression>& expression) {
         checkErrorAndVisit(expression);
-        m_stack.takeLast(); // We don't need to do anything with the result.
+        takeLastValue(); // We don't need to do anything with the result.
     }), forLoop.initialization());
 
     emitLoop(LoopConditionLocation::BeforeBody, forLoop.condition(), forLoop.increment(), forLoop.body());
@@ -315,7 +354,7 @@ void FunctionDefinitionWriter::visit(AST::ForLoop& forLoop)
 void FunctionDefinitionWriter::visit(AST::IfStatement& ifStatement)
 {
     checkErrorAndVisit(ifStatement.conditional());
-    m_stringBuilder.append(makeString("if (", m_stack.takeLast(), ") {\n"));
+    m_stringBuilder.append(makeString("if (", takeLastValue(), ") {\n"));
     checkErrorAndVisit(ifStatement.body());
     if (ifStatement.elseBody()) {
         m_stringBuilder.append("} else {\n");
@@ -330,10 +369,10 @@ void FunctionDefinitionWriter::visit(AST::Return& returnStatement)
         checkErrorAndVisit(*returnStatement.value());
         if (m_entryPointScaffolding) {
             auto variableName = generateNextVariableName();
-            m_stringBuilder.append(m_entryPointScaffolding->pack(m_stack.takeLast(), variableName));
+            m_stringBuilder.append(m_entryPointScaffolding->pack(takeLastValue(), variableName));
             m_stringBuilder.append(makeString("return ", variableName, ";\n"));
         } else
-            m_stringBuilder.append(makeString("return ", m_stack.takeLast(), ";\n"));
+            m_stringBuilder.append(makeString("return ", takeLastValue(), ";\n"));
     } else
         m_stringBuilder.append("return;\n");
 }
@@ -342,7 +381,7 @@ void FunctionDefinitionWriter::visit(AST::SwitchStatement& switchStatement)
 {
     checkErrorAndVisit(switchStatement.value());
 
-    m_stringBuilder.append(makeString("switch (", m_stack.takeLast(), ") {"));
+    m_stringBuilder.append(makeString("switch (", takeLastValue(), ") {"));
     for (auto& switchCase : switchStatement.switchCases())
         checkErrorAndVisit(switchCase);
     m_stringBuilder.append("}\n");
@@ -375,7 +414,7 @@ void FunctionDefinitionWriter::visit(AST::IntegerLiteral& integerLiteral)
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(integerLiteral.resolvedType());
     m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", integerLiteral.value(), ");\n"));
-    m_stack.append(variableName);
+    appendRightValue(integerLiteral, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::UnsignedIntegerLiteral& unsignedIntegerLiteral)
@@ -383,7 +422,7 @@ void FunctionDefinitionWriter::visit(AST::UnsignedIntegerLiteral& unsignedIntege
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(unsignedIntegerLiteral.resolvedType());
     m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", unsignedIntegerLiteral.value(), ");\n"));
-    m_stack.append(variableName);
+    appendRightValue(unsignedIntegerLiteral, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::FloatLiteral& floatLiteral)
@@ -391,7 +430,7 @@ void FunctionDefinitionWriter::visit(AST::FloatLiteral& floatLiteral)
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(floatLiteral.resolvedType());
     m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", floatLiteral.value(), ");\n"));
-    m_stack.append(variableName);
+    appendRightValue(floatLiteral, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::NullLiteral& nullLiteral)
@@ -407,7 +446,7 @@ void FunctionDefinitionWriter::visit(AST::NullLiteral& nullLiteral)
     else
         m_stringBuilder.append("nullptr");
     m_stringBuilder.append(";\n");
-    m_stack.append(variableName);
+    appendRightValue(nullLiteral, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::BooleanLiteral& booleanLiteral)
@@ -415,7 +454,7 @@ void FunctionDefinitionWriter::visit(AST::BooleanLiteral& booleanLiteral)
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(booleanLiteral.resolvedType());
     m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", booleanLiteral.value() ? "true" : "false", ");\n"));
-    m_stack.append(variableName);
+    appendRightValue(booleanLiteral, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::EnumerationMemberLiteral& enumerationMemberLiteral)
@@ -425,7 +464,7 @@ void FunctionDefinitionWriter::visit(AST::EnumerationMemberLiteral& enumerationM
     auto variableName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(enumerationMemberLiteral.resolvedType());
     m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = ", mangledTypeName, '.', m_typeNamer.mangledNameForEnumerationMember(*enumerationMemberLiteral.enumerationMember()), ";\n"));
-    m_stack.append(variableName);
+    appendRightValue(enumerationMemberLiteral, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::Expression& expression)
@@ -433,37 +472,39 @@ void FunctionDefinitionWriter::visit(AST::Expression& expression)
     Visitor::visit(expression);
 }
 
-void FunctionDefinitionWriter::visit(AST::DotExpression&)
+void FunctionDefinitionWriter::visit(AST::DotExpression& dotExpression)
 {
     // This should be lowered already.
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED().
     notImplemented();
-    m_stack.append("dummy");
+    appendRightValue(dotExpression, "dummy");
 }
 
 void FunctionDefinitionWriter::visit(AST::GlobalVariableReference& globalVariableReference)
 {
-    auto variableName = generateNextVariableName();
+    auto valueName = generateNextVariableName();
+    auto pointerName = generateNextVariableName();
     auto mangledTypeName = m_typeNamer.mangledNameForType(globalVariableReference.resolvedType());
     checkErrorAndVisit(globalVariableReference.base());
-    m_stringBuilder.append(makeString("thread ", mangledTypeName, "& ", variableName, " = ", m_stack.takeLast(), "->", m_typeNamer.mangledNameForStructureElement(globalVariableReference.structField()), ";\n"));
-    m_stack.append(variableName);
+    m_stringBuilder.append(makeString("thread ", mangledTypeName, "* ", pointerName, " = &", takeLastValue(), "->", m_typeNamer.mangledNameForStructureElement(globalVariableReference.structField()), ";\n"));
+    m_stringBuilder.append(makeString(mangledTypeName, ' ', valueName, " = ", "*", pointerName, ";\n"));
+    appendLeftValue(globalVariableReference, valueName, pointerName);
 }
 
-void FunctionDefinitionWriter::visit(AST::IndexExpression&)
+void FunctionDefinitionWriter::visit(AST::IndexExpression& indexExpression)
 {
     // This should be lowered already.
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED().
     notImplemented();
-    m_stack.append("dummy");
+    appendRightValue(indexExpression, "dummy");
 }
 
-void FunctionDefinitionWriter::visit(AST::PropertyAccessExpression&)
+void FunctionDefinitionWriter::visit(AST::PropertyAccessExpression& propertyAccessExpression)
 {
     // This should be lowered already.
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED().
     notImplemented();
-    m_stack.append("dummy");
+    appendRightValue(propertyAccessExpression, "dummy");
 }
 
 void FunctionDefinitionWriter::visit(AST::VariableDeclaration& variableDeclaration)
@@ -475,7 +516,7 @@ void FunctionDefinitionWriter::visit(AST::VariableDeclaration& variableDeclarati
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198160 Implement qualifiers.
     if (variableDeclaration.initializer()) {
         checkErrorAndVisit(*variableDeclaration.initializer());
-        m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, " = ", m_stack.takeLast(), ";\n"));
+        m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, " = ", takeLastValue(), ";\n"));
     } else
         m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, ";\n"));
 }
@@ -483,11 +524,11 @@ void FunctionDefinitionWriter::visit(AST::VariableDeclaration& variableDeclarati
 void FunctionDefinitionWriter::visit(AST::AssignmentExpression& assignmentExpression)
 {
     checkErrorAndVisit(assignmentExpression.left());
-    auto leftName = m_stack.takeLast();
+    auto pointerName = takeLastLeftValue();
     checkErrorAndVisit(assignmentExpression.right());
-    auto rightName = m_stack.takeLast();
-    m_stringBuilder.append(makeString(leftName, " = ", rightName, ";\n"));
-    m_stack.append(rightName);
+    auto rightName = takeLastValue();
+    m_stringBuilder.append(makeString("if (", pointerName, ") *", pointerName, " = ", rightName, ";\n"));
+    appendRightValue(assignmentExpression, rightName);
 }
 
 void FunctionDefinitionWriter::visit(AST::CallExpression& callExpression)
@@ -495,7 +536,7 @@ void FunctionDefinitionWriter::visit(AST::CallExpression& callExpression)
     Vector<String> argumentNames;
     for (auto& argument : callExpression.arguments()) {
         checkErrorAndVisit(argument);
-        argumentNames.append(m_stack.takeLast());
+        argumentNames.append(takeLastValue());
     }
     ASSERT(callExpression.function());
     auto iterator = m_functionMapping.find(callExpression.function());
@@ -508,7 +549,7 @@ void FunctionDefinitionWriter::visit(AST::CallExpression& callExpression)
         m_stringBuilder.append(argumentNames[i]);
     }
     m_stringBuilder.append(");\n");
-    m_stack.append(variableName);
+    appendRightValue(callExpression, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::CommaExpression& commaExpression)
@@ -516,26 +557,30 @@ void FunctionDefinitionWriter::visit(AST::CommaExpression& commaExpression)
     String result;
     for (auto& expression : commaExpression.list()) {
         checkErrorAndVisit(expression);
-        result = m_stack.takeLast();
+        result = takeLastValue();
     }
-    m_stack.append(result);
+    appendRightValue(commaExpression, result);
 }
 
 void FunctionDefinitionWriter::visit(AST::DereferenceExpression& dereferenceExpression)
 {
     checkErrorAndVisit(dereferenceExpression.pointer());
-    auto right = m_stack.takeLast();
+    auto right = takeLastValue();
     auto variableName = generateNextVariableName();
-    m_stringBuilder.append(makeString(AST::toString(*dereferenceExpression.typeAnnotation().leftAddressSpace()), ' ', m_typeNamer.mangledNameForType(dereferenceExpression.resolvedType()), "& ", variableName, " = *", right, ";\n"));
-    m_stack.append(variableName);
+    auto pointerName = generateNextVariableName();
+    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(dereferenceExpression.pointer().resolvedType()), ' ', pointerName, " = ", right, ";\n"));
+    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(dereferenceExpression.resolvedType()), ' ', variableName, ";\n"));
+    m_stringBuilder.append(makeString("if (", pointerName, ") ", variableName, " = *", right, ";\n"));
+    m_stringBuilder.append(makeString("else ", memsetZeroFunctionName, '(', variableName, ");\n"));
+    appendLeftValue(dereferenceExpression, variableName, pointerName);
 }
 
 void FunctionDefinitionWriter::visit(AST::LogicalExpression& logicalExpression)
 {
     checkErrorAndVisit(logicalExpression.left());
-    auto left = m_stack.takeLast();
+    auto left = takeLastValue();
     checkErrorAndVisit(logicalExpression.right());
-    auto right = m_stack.takeLast();
+    auto right = takeLastValue();
     auto variableName = generateNextVariableName();
     m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(logicalExpression.resolvedType()), ' ', variableName, " = ", left));
     switch (logicalExpression.type()) {
@@ -548,22 +593,24 @@ void FunctionDefinitionWriter::visit(AST::LogicalExpression& logicalExpression)
         break;
     }
     m_stringBuilder.append(makeString(right, ";\n"));
-    m_stack.append(variableName);
+    appendRightValue(logicalExpression, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::LogicalNotExpression& logicalNotExpression)
 {
     checkErrorAndVisit(logicalNotExpression.operand());
-    auto operand = m_stack.takeLast();
+    auto operand = takeLastValue();
     auto variableName = generateNextVariableName();
     m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(logicalNotExpression.resolvedType()), ' ', variableName, " = !", operand, ";\n"));
-    m_stack.append(variableName);
+    appendRightValue(logicalNotExpression, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::MakeArrayReferenceExpression& makeArrayReferenceExpression)
 {
     checkErrorAndVisit(makeArrayReferenceExpression.leftValue());
-    auto lValue = m_stack.takeLast();
+    // 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()))
@@ -573,16 +620,16 @@ void FunctionDefinitionWriter::visit(AST::MakeArrayReferenceExpression& makeArra
         m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { &(", lValue, "[0]), ", arrayType.numElements(), " };\n"));
     } else
         m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { &", lValue, ", 1 };\n"));
-    m_stack.append(variableName);
+    appendRightValue(makeArrayReferenceExpression, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::MakePointerExpression& makePointerExpression)
 {
     checkErrorAndVisit(makePointerExpression.leftValue());
-    auto lValue = m_stack.takeLast();
+    auto pointer = takeLastLeftValue();
     auto variableName = generateNextVariableName();
-    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(makePointerExpression.resolvedType()), ' ', variableName, " = &", lValue, ";\n"));
-    m_stack.append(variableName);
+    m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(makePointerExpression.resolvedType()), ' ', variableName, " = ", pointer, ";\n"));
+    appendRightValue(makePointerExpression, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::ReadModifyWriteExpression&)
@@ -594,19 +641,19 @@ void FunctionDefinitionWriter::visit(AST::ReadModifyWriteExpression&)
 void FunctionDefinitionWriter::visit(AST::TernaryExpression& ternaryExpression)
 {
     checkErrorAndVisit(ternaryExpression.predicate());
-    auto check = m_stack.takeLast();
+    auto check = takeLastValue();
 
     auto variableName = generateNextVariableName();
     m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(ternaryExpression.resolvedType()), ' ', variableName, ";\n"));
 
     m_stringBuilder.append(makeString("if (", check, ") {\n"));
     checkErrorAndVisit(ternaryExpression.bodyExpression());
-    m_stringBuilder.append(makeString(variableName, " = ", m_stack.takeLast(), ";\n"));
+    m_stringBuilder.append(makeString(variableName, " = ", takeLastValue(), ";\n"));
     m_stringBuilder.append("} else {\n");
     checkErrorAndVisit(ternaryExpression.elseExpression());
-    m_stringBuilder.append(makeString(variableName, " = ", m_stack.takeLast(), ";\n"));
+    m_stringBuilder.append(makeString(variableName, " = ", takeLastValue(), ";\n"));
     m_stringBuilder.append("}\n");
-    m_stack.append(variableName);
+    appendRightValue(ternaryExpression, variableName);
 }
 
 void FunctionDefinitionWriter::visit(AST::VariableReference& variableReference)
@@ -614,7 +661,9 @@ void FunctionDefinitionWriter::visit(AST::VariableReference& variableReference)
     ASSERT(variableReference.variable());
     auto iterator = m_variableMapping.find(variableReference.variable());
     ASSERT(iterator != m_variableMapping.end());
-    m_stack.append(iterator->value);
+    auto pointerName = generateNextVariableName();
+    m_stringBuilder.append(makeString("thread ", m_typeNamer.mangledNameForType(variableReference.resolvedType()), "* ", pointerName, " = &", iterator->value, ";\n"));
+    appendLeftValue(variableReference, iterator->value, pointerName);
 }
 
 String FunctionDefinitionWriter::constantExpressionString(AST::ConstantExpression& constantExpression)
index db3947b..aba39d5 100644 (file)
@@ -81,7 +81,7 @@ static String atomicName(String input)
         return "fetch_xor"_str;
 }
 
-String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclaration, String& outputFunctionName, Intrinsics& intrinsics, TypeNamer& typeNamer)
+String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclaration, String& outputFunctionName, Intrinsics& intrinsics, TypeNamer& typeNamer, const char* memsetZeroFunctionName)
 {
     StringBuilder stringBuilder;
     if (nativeFunctionDeclaration.isCast()) {
@@ -89,8 +89,7 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         if (!nativeFunctionDeclaration.parameters().size()) {
             stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, "() {\n"));
             stringBuilder.append(makeString("    ", metalReturnName, " x;\n"));
-            stringBuilder.append("    thread char* ptr = static_cast<thread char*>(static_cast<thread void*>(&x));\n");
-            stringBuilder.append(makeString("    for (size_t i = 0; i < sizeof(", metalReturnName, "); ++i) ptr[i] = 0;\n"));
+            stringBuilder.append(makeString("    ", memsetZeroFunctionName, "(x);\n"));
             stringBuilder.append("    return x;\n");
             stringBuilder.append("}\n");
             return stringBuilder.toString();
@@ -214,38 +213,14 @@ String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclara
         return stringBuilder.toString();
     }
 
-    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("    return m[i];\n"));
-        stringBuilder.append("}\n");
-        return stringBuilder.toString();
-    }
-
     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());
-        auto fieldName = nativeFunctionDeclaration.name().substring("operator&[]."_str.length());
         stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " v, ", metalParameter2Name, " n) {\n"));
-        stringBuilder.append(makeString("    return &(v.pointer[n]);\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("    m[i] = v;\n"));
-        stringBuilder.append(makeString("    return m;\n"));
+        stringBuilder.append("    if (n < v.length) return &(v.pointer[n]);\n");
+        stringBuilder.append("    return nullptr;\n");
         stringBuilder.append("}\n");
         return stringBuilder.toString();
     }
index 257bb85..7dd83ec 100644 (file)
@@ -45,7 +45,7 @@ namespace Metal {
 
 class TypeNamer;
 
-String writeNativeFunction(AST::NativeFunctionDeclaration&, String& outputFunctionName, Intrinsics&, TypeNamer&);
+String writeNativeFunction(AST::NativeFunctionDeclaration&, String& outputFunctionName, Intrinsics&, TypeNamer&, const char* memsetZeroFunctionName);
 
 }
 
index c3d8272..555ed8a 100644 (file)
@@ -393,7 +393,7 @@ void TypeNamer::emitUnnamedTypeDefinition(BaseTypeNameNode& baseTypeNameNode, Ha
         ASSERT(baseTypeNameNode.parent());
         stringBuilder.append(makeString("struct ", arrayReferenceType.mangledName(), "{ \n"));
         stringBuilder.append(makeString("    ", toString(arrayReferenceType.addressSpace()), " ", arrayReferenceType.parent()->mangledName(), "* pointer;\n"));
-        stringBuilder.append("    uint length;\n");
+        stringBuilder.append("    uint32_t length;\n");
         stringBuilder.append("};\n");
     } else {
         auto& arrayType = downcast<ArrayTypeNameNode>(baseTypeNameNode);
index 610b5fe..1504624 100644 (file)
@@ -110,7 +110,7 @@ public:
 
         auto rhs = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variable));
         rhs->setType(variable.type()->clone());
-        rhs->setTypeAnnotation(AST::RightValue());
+        rhs->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread });
 
         auto assignment = makeUniqueRef<AST::AssignmentExpression>(variable.origin(), WTFMove(lhs), WTFMove(rhs));
         assignment->setType(variable.type()->clone());
@@ -136,7 +136,7 @@ public:
 
             auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(functionDefinition.origin(), WTFMove(structVariableReference));
             makePointerExpression->setType(m_pointerToStructType->clone());
-            makePointerExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread });
+            makePointerExpression->setTypeAnnotation(AST::RightValue());
 
             auto pointerDeclaration = makeUniqueRef<AST::VariableDeclaration>(functionDefinition.origin(), AST::Qualifiers(),
                 m_pointerToStructType->clone(), "wrapper"_s, WTF::nullopt, Optional<UniqueRef<AST::Expression>>(WTFMove(makePointerExpression)));
index 75b4ae3..2a3b9b8 100644 (file)
@@ -685,7 +685,11 @@ void PropertyResolver::visit(AST::ReadModifyWriteExpression& readModifyWriteExpr
             expressions.append(WTFMove(assignmentExpression));
         }
 
-        return {{ WTFMove(expressions), readModifyWriteExpression.newVariableReference() }};
+        auto variableReference = readModifyWriteExpression.newVariableReference();
+        variableReference->setType(readModifyWriteExpression.leftValue().resolvedType().clone());
+        variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right?
+
+        return {{ WTFMove(expressions),  WTFMove(variableReference) }};
     });
 
     if (!modifyResult) {
index 5170e1a..dc0cfe7 100644 (file)
@@ -439,6 +439,9 @@ native uint operator+(uint, uint);
 native bool operator<(int, int);
 native bool operator<(uint, uint);
 native bool operator<(float, float);
+native bool operator==(float, float);
+native bool operator==(int, int);
+native bool operator==(thread int*, thread int*);
 native float operator*(float, float);
 
 native bool operator.x(bool2);
index d6eced4..e81f7ca 100644 (file)
@@ -92,7 +92,10 @@ static Optional<WHLSL::ComputeDimensions> trySetFunctions(const char* const func
         BEGIN_BLOCK_OBJC_EXCEPTIONS;
         computeLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource options:nil error:&error]);
         END_BLOCK_OBJC_EXCEPTIONS;
-
+#ifndef NDEBUG
+        if (!computeLibrary)
+            NSLog(@"%@", error);
+#endif
         ASSERT(computeLibrary);
         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Once we zero-fill variables, there should be no warnings, so we should be able to ASSERT(!error) here.
 
index 1745df0..f56661d 100644 (file)
@@ -416,6 +416,10 @@ static bool trySetFunctions(const char* const functionName, const GPUPipelineSta
         vertexLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource options:nil error:&error]);
         END_BLOCK_OBJC_EXCEPTIONS;
 
+#ifndef NDEBUG
+        if (!vertexLibrary)
+            NSLog(@"%@", error);
+#endif
         ASSERT(vertexLibrary);
         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Once we zero-fill variables, there should be no warnings, so we should be able to ASSERT(!error) here.