Diff
Modified: trunk/LayoutTests/ChangeLog (245944 => 245945)
--- trunk/LayoutTests/ChangeLog 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/LayoutTests/ChangeLog 2019-05-31 04:31:54 UTC (rev 245945)
@@ -1,3 +1,20 @@
+2019-05-30 Saam Barati <[email protected]>
+
+ [WHLSL] Enforce variable lifetimes
+ https://bugs.webkit.org/show_bug.cgi?id=195794
+ <rdar://problem/50746293>
+
+ Reviewed by Myles C. Maxfield.
+
+ * webgpu/whlsl-ensure-proper-variable-lifetime-2-expected.html: Added.
+ * webgpu/whlsl-ensure-proper-variable-lifetime-2.html: Added.
+ * webgpu/whlsl-ensure-proper-variable-lifetime-3-expected.html: Added.
+ * webgpu/whlsl-ensure-proper-variable-lifetime-3.html: Added.
+ * webgpu/whlsl-ensure-proper-variable-lifetime-expected.html: Added.
+ * webgpu/whlsl-ensure-proper-variable-lifetime.html: Added.
+ * webgpu/whlsl-return-local-variable-expected.html: Added.
+ * webgpu/whlsl-return-local-variable.html: Added.
+
2019-05-30 Ryan Haddad <[email protected]>
Unreviewed, rolling out r245890, 245887.
Added: trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2-expected.html (0 => 245945)
--- trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2-expected.html (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2-expected.html 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+async function start() {
+ const canvas = document.getElementById("canvas");
+ const context = canvas.getContext("2d");
+ context.fillStyle = "blue";
+ context.fillRect(0, 0, 400, 400);
+ context.fillStyle = "white";
+ context.fillRect(100, 100, 200, 200);
+}
+window.addEventListener("load", start);
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2.html (0 => 245945)
--- trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2.html (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-2.html 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,153 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const shaderSource = `
+struct VertexOut {
+ float4 position : SV_Position;
+ float shade : attribute(0);
+}
+
+float assignToPtr(thread float* ptr, float value) {
+ return *ptr = value;
+}
+
+thread float* realPtr(float value)
+{
+ return &value;
+}
+
+thread float* firstPtr(float value) {
+ return realPtr(value);
+}
+
+thread float* secondPtr(float value) {
+ return firstPtr(value);
+}
+
+vertex VertexOut vertexShader(float4 position : attribute(0), float shade : attribute(1)) {
+ VertexOut result;
+
+ thread float* ptrToShade = firstPtr(shade);
+ thread float* ptrToShade2 = secondPtr(1.0);
+
+ float dummy;
+ thread float* dummyPtr = &dummy;
+
+ dummy = assignToPtr(ptrToShade2, 0.0);
+ thread float* dummy2 = realPtr(shade);
+
+ result.position = position;
+
+ result.shade = *ptrToShade2;
+
+ return result;
+}
+
+fragment float4 fragmentShader(float shade : attribute(0)) : SV_Target 0 {
+ return float4(shade, shade, shade, 1.0);
+}
+`;
+async function start() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+
+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true});
+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"};
+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"};
+ const primitiveTopology = "triangle-strip";
+ const rasterizationState = {frontFace: "cw", cullMode: "none"};
+ const alphaBlend = {};
+ const colorBlend = {};
+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+ const depthStencilState = null;
+
+ const attribute0 = {shaderLocation: 0, format: "float4"};
+ const attribute1 = {shaderLocation: 1, format: "float", offset: 16};
+ const attributes = [attribute0, attribute1];
+ const input0 = {stride: 20, attributeSet: attributes};
+ const inputs = [input0];
+ const vertexInput = {vertexBuffers: inputs};
+
+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]};
+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor);
+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]};
+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+ const vertexBuffer0Descriptor = {size: Float32Array.BYTES_PER_ELEMENT * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+ const vertexBuffer0 = device.createBuffer(vertexBuffer0Descriptor);
+ const vertexBuffer0ArrayBuffer = await vertexBuffer0.mapWriteAsync();
+ const vertexBuffer0Float32Array = new Float32Array(vertexBuffer0ArrayBuffer);
+ vertexBuffer0Float32Array[0] = -0.5;
+ vertexBuffer0Float32Array[1] = -0.5;
+ vertexBuffer0Float32Array[2] = 1.0;
+ vertexBuffer0Float32Array[3] = 1.0;
+ vertexBuffer0Float32Array[4] = 1.0;
+
+ vertexBuffer0Float32Array[5] = -0.5;
+ vertexBuffer0Float32Array[6] = 0.5;
+ vertexBuffer0Float32Array[7] = 1.0;
+ vertexBuffer0Float32Array[8] = 1.0;
+ vertexBuffer0Float32Array[9] = 1.0;
+
+ vertexBuffer0Float32Array[10] = 0.5;
+ vertexBuffer0Float32Array[11] = -0.5;
+ vertexBuffer0Float32Array[12] = 1.0;
+ vertexBuffer0Float32Array[13] = 1.0;
+ vertexBuffer0Float32Array[14] = 1.0;
+
+ vertexBuffer0Float32Array[15] = 0.5;
+ vertexBuffer0Float32Array[16] = 0.5;
+ vertexBuffer0Float32Array[17] = 1.0;
+ vertexBuffer0Float32Array[18] = 1.0;
+ vertexBuffer0Float32Array[19] = 1.0;
+ vertexBuffer0.unmap();
+
+ const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE};
+ const resourceBuffer = device.createBuffer(resourceBufferDescriptor);
+ const resourceBufferArrayBuffer = await resourceBuffer.mapWriteAsync();
+ const resourceBufferFloat32Array = new Float32Array(resourceBufferArrayBuffer);
+ resourceBufferFloat32Array[0] = 1;
+ resourceBuffer.unmap();
+
+ const bufferBinding = {buffer: resourceBuffer, size: 4};
+ const bindGroupBinding = {binding: 0, resource: bufferBinding};
+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]};
+ const bindGroup = device.createBindGroup(bindGroupDescriptor);
+
+ const canvas = document.getElementById("canvas");
+ const context = canvas.getContext("gpu");
+ const swapChainDescriptor = {device, format: "bgra8unorm"};
+ const swapChain = context.configureSwapChain(swapChainDescriptor);
+ const outputTexture = swapChain.getCurrentTexture();
+ const outputTextureView = outputTexture.createDefaultView();
+
+ const commandEncoder = device.createCommandEncoder(); // {}
+ const red = {r: 0, g: 0, b: 1, a: 1};
+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+ const depthStencilAttachment = null;
+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+ renderPassEncoder.setPipeline(renderPipeline);
+ renderPassEncoder.setBindGroup(0, bindGroup);
+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer0], [0]);
+ renderPassEncoder.draw(4, 1, 0, 0);
+ renderPassEncoder.endPass();
+ const commandBuffer = commandEncoder.finish();
+ device.getQueue().submit([commandBuffer]);
+
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+if (window.testRunner)
+ testRunner.waitUntilDone();
+window.addEventListener("load", start);
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-3-expected.html (0 => 245945)
--- trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-3-expected.html (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-3-expected.html 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+async function start() {
+ const canvas = document.getElementById("canvas");
+ const context = canvas.getContext("2d");
+ context.fillStyle = "blue";
+ context.fillRect(0, 0, 400, 400);
+ context.fillStyle = "white";
+ context.fillRect(100, 100, 200, 200);
+}
+window.addEventListener("load", start);
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-3.html (0 => 245945)
--- trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-3.html (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-3.html 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,154 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const shaderSource = `
+struct VertexOut {
+ float4 position : SV_Position;
+ float shade : attribute(0);
+}
+
+float assignToPtr(thread float* ptr, float value) {
+ return *ptr = value;
+}
+
+thread float* realPtr(float value)
+{
+ float v = value;
+ return &v;
+}
+
+thread float* firstPtr(float value) {
+ return realPtr(value);
+}
+
+thread float* secondPtr(float value) {
+ return firstPtr(value);
+}
+
+vertex VertexOut vertexShader(float4 position : attribute(0), float shade : attribute(1)) {
+ VertexOut result;
+
+ thread float* ptrToShade = firstPtr(shade);
+ thread float* ptrToShade2 = secondPtr(1.0);
+
+ float dummy;
+ thread float* dummyPtr = &dummy;
+
+ dummy = assignToPtr(ptrToShade2, 0.0);
+ thread float* dummy2 = realPtr(shade);
+
+ result.position = position;
+
+ result.shade = *ptrToShade2;
+
+ return result;
+}
+
+fragment float4 fragmentShader(float shade : attribute(0)) : SV_Target 0 {
+ return float4(shade, shade, shade, 1.0);
+}
+`;
+async function start() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+
+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true});
+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"};
+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"};
+ const primitiveTopology = "triangle-strip";
+ const rasterizationState = {frontFace: "cw", cullMode: "none"};
+ const alphaBlend = {};
+ const colorBlend = {};
+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+ const depthStencilState = null;
+
+ const attribute0 = {shaderLocation: 0, format: "float4"};
+ const attribute1 = {shaderLocation: 1, format: "float", offset: 16};
+ const attributes = [attribute0, attribute1];
+ const input0 = {stride: 20, attributeSet: attributes};
+ const inputs = [input0];
+ const vertexInput = {vertexBuffers: inputs};
+
+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]};
+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor);
+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]};
+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+ const vertexBuffer0Descriptor = {size: Float32Array.BYTES_PER_ELEMENT * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+ const vertexBuffer0 = device.createBuffer(vertexBuffer0Descriptor);
+ const vertexBuffer0ArrayBuffer = await vertexBuffer0.mapWriteAsync();
+ const vertexBuffer0Float32Array = new Float32Array(vertexBuffer0ArrayBuffer);
+ vertexBuffer0Float32Array[0] = -0.5;
+ vertexBuffer0Float32Array[1] = -0.5;
+ vertexBuffer0Float32Array[2] = 1.0;
+ vertexBuffer0Float32Array[3] = 1.0;
+ vertexBuffer0Float32Array[4] = 1.0;
+
+ vertexBuffer0Float32Array[5] = -0.5;
+ vertexBuffer0Float32Array[6] = 0.5;
+ vertexBuffer0Float32Array[7] = 1.0;
+ vertexBuffer0Float32Array[8] = 1.0;
+ vertexBuffer0Float32Array[9] = 1.0;
+
+ vertexBuffer0Float32Array[10] = 0.5;
+ vertexBuffer0Float32Array[11] = -0.5;
+ vertexBuffer0Float32Array[12] = 1.0;
+ vertexBuffer0Float32Array[13] = 1.0;
+ vertexBuffer0Float32Array[14] = 1.0;
+
+ vertexBuffer0Float32Array[15] = 0.5;
+ vertexBuffer0Float32Array[16] = 0.5;
+ vertexBuffer0Float32Array[17] = 1.0;
+ vertexBuffer0Float32Array[18] = 1.0;
+ vertexBuffer0Float32Array[19] = 1.0;
+ vertexBuffer0.unmap();
+
+ const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE};
+ const resourceBuffer = device.createBuffer(resourceBufferDescriptor);
+ const resourceBufferArrayBuffer = await resourceBuffer.mapWriteAsync();
+ const resourceBufferFloat32Array = new Float32Array(resourceBufferArrayBuffer);
+ resourceBufferFloat32Array[0] = 1;
+ resourceBuffer.unmap();
+
+ const bufferBinding = {buffer: resourceBuffer, size: 4};
+ const bindGroupBinding = {binding: 0, resource: bufferBinding};
+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]};
+ const bindGroup = device.createBindGroup(bindGroupDescriptor);
+
+ const canvas = document.getElementById("canvas");
+ const context = canvas.getContext("gpu");
+ const swapChainDescriptor = {device, format: "bgra8unorm"};
+ const swapChain = context.configureSwapChain(swapChainDescriptor);
+ const outputTexture = swapChain.getCurrentTexture();
+ const outputTextureView = outputTexture.createDefaultView();
+
+ const commandEncoder = device.createCommandEncoder(); // {}
+ const red = {r: 0, g: 0, b: 1, a: 1};
+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+ const depthStencilAttachment = null;
+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+ renderPassEncoder.setPipeline(renderPipeline);
+ renderPassEncoder.setBindGroup(0, bindGroup);
+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer0], [0]);
+ renderPassEncoder.draw(4, 1, 0, 0);
+ renderPassEncoder.endPass();
+ const commandBuffer = commandEncoder.finish();
+ device.getQueue().submit([commandBuffer]);
+
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+if (window.testRunner)
+ testRunner.waitUntilDone();
+window.addEventListener("load", start);
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-expected.html (0 => 245945)
--- trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-expected.html (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime-expected.html 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+async function start() {
+ const canvas = document.getElementById("canvas");
+ const context = canvas.getContext("2d");
+ context.fillStyle = "blue";
+ context.fillRect(0, 0, 400, 400);
+ context.fillStyle = "white";
+ context.fillRect(100, 100, 200, 200);
+}
+window.addEventListener("load", start);
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime.html (0 => 245945)
--- trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime.html (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-ensure-proper-variable-lifetime.html 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,153 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const shaderSource = `
+struct VertexOut {
+ float4 position : SV_Position;
+ float shade : attribute(0);
+}
+
+float assignToPtr(thread float* ptr, float value) {
+ return *ptr = value;
+}
+
+thread float* realPtr(float value)
+{
+ return &value;
+}
+
+thread float* firstPtr(float value) {
+ return realPtr(value);
+}
+
+thread float* secondPtr(float value) {
+ return firstPtr(value);
+}
+
+vertex VertexOut vertexShader(float4 position : attribute(0), float shade : attribute(1)) {
+ VertexOut result;
+
+ thread float* ptrToShade = firstPtr(shade);
+ thread float* ptrToShade2 = secondPtr(1.0);
+
+ float dummy;
+ thread float* dummyPtr = &dummy;
+
+ dummy = assignToPtr(ptrToShade2, 0.0);
+ dummy = assignToPtr(ptrToShade, shade);
+
+ result.position = position;
+
+ result.shade = *ptrToShade2;
+
+ return result;
+}
+
+fragment float4 fragmentShader(float shade : attribute(0)) : SV_Target 0 {
+ return float4(shade, shade, shade, 1.0);
+}
+`;
+async function start() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+
+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true});
+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"};
+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"};
+ const primitiveTopology = "triangle-strip";
+ const rasterizationState = {frontFace: "cw", cullMode: "none"};
+ const alphaBlend = {};
+ const colorBlend = {};
+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+ const depthStencilState = null;
+
+ const attribute0 = {shaderLocation: 0, format: "float4"};
+ const attribute1 = {shaderLocation: 1, format: "float", offset: 16};
+ const attributes = [attribute0, attribute1];
+ const input0 = {stride: 20, attributeSet: attributes};
+ const inputs = [input0];
+ const vertexInput = {vertexBuffers: inputs};
+
+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]};
+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor);
+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]};
+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+ const vertexBuffer0Descriptor = {size: Float32Array.BYTES_PER_ELEMENT * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+ const vertexBuffer0 = device.createBuffer(vertexBuffer0Descriptor);
+ const vertexBuffer0ArrayBuffer = await vertexBuffer0.mapWriteAsync();
+ const vertexBuffer0Float32Array = new Float32Array(vertexBuffer0ArrayBuffer);
+ vertexBuffer0Float32Array[0] = -0.5;
+ vertexBuffer0Float32Array[1] = -0.5;
+ vertexBuffer0Float32Array[2] = 1.0;
+ vertexBuffer0Float32Array[3] = 1.0;
+ vertexBuffer0Float32Array[4] = 1.0;
+
+ vertexBuffer0Float32Array[5] = -0.5;
+ vertexBuffer0Float32Array[6] = 0.5;
+ vertexBuffer0Float32Array[7] = 1.0;
+ vertexBuffer0Float32Array[8] = 1.0;
+ vertexBuffer0Float32Array[9] = 1.0;
+
+ vertexBuffer0Float32Array[10] = 0.5;
+ vertexBuffer0Float32Array[11] = -0.5;
+ vertexBuffer0Float32Array[12] = 1.0;
+ vertexBuffer0Float32Array[13] = 1.0;
+ vertexBuffer0Float32Array[14] = 1.0;
+
+ vertexBuffer0Float32Array[15] = 0.5;
+ vertexBuffer0Float32Array[16] = 0.5;
+ vertexBuffer0Float32Array[17] = 1.0;
+ vertexBuffer0Float32Array[18] = 1.0;
+ vertexBuffer0Float32Array[19] = 1.0;
+ vertexBuffer0.unmap();
+
+ const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE};
+ const resourceBuffer = device.createBuffer(resourceBufferDescriptor);
+ const resourceBufferArrayBuffer = await resourceBuffer.mapWriteAsync();
+ const resourceBufferFloat32Array = new Float32Array(resourceBufferArrayBuffer);
+ resourceBufferFloat32Array[0] = 1;
+ resourceBuffer.unmap();
+
+ const bufferBinding = {buffer: resourceBuffer, size: 4};
+ const bindGroupBinding = {binding: 0, resource: bufferBinding};
+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]};
+ const bindGroup = device.createBindGroup(bindGroupDescriptor);
+
+ const canvas = document.getElementById("canvas");
+ const context = canvas.getContext("gpu");
+ const swapChainDescriptor = {device, format: "bgra8unorm"};
+ const swapChain = context.configureSwapChain(swapChainDescriptor);
+ const outputTexture = swapChain.getCurrentTexture();
+ const outputTextureView = outputTexture.createDefaultView();
+
+ const commandEncoder = device.createCommandEncoder(); // {}
+ const red = {r: 0, g: 0, b: 1, a: 1};
+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+ const depthStencilAttachment = null;
+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+ renderPassEncoder.setPipeline(renderPipeline);
+ renderPassEncoder.setBindGroup(0, bindGroup);
+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer0], [0]);
+ renderPassEncoder.draw(4, 1, 0, 0);
+ renderPassEncoder.endPass();
+ const commandBuffer = commandEncoder.finish();
+ device.getQueue().submit([commandBuffer]);
+
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+if (window.testRunner)
+ testRunner.waitUntilDone();
+window.addEventListener("load", start);
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/webgpu/whlsl-return-local-variable-expected.html (0 => 245945)
--- trunk/LayoutTests/webgpu/whlsl-return-local-variable-expected.html (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-return-local-variable-expected.html 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+async function start() {
+ const canvas = document.getElementById("canvas");
+ const context = canvas.getContext("2d");
+ context.fillStyle = "blue";
+ context.fillRect(0, 0, 400, 400);
+ context.fillStyle = "white";
+ context.fillRect(100, 100, 200, 200);
+}
+window.addEventListener("load", start);
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/webgpu/whlsl-return-local-variable.html (0 => 245945)
--- trunk/LayoutTests/webgpu/whlsl-return-local-variable.html (rev 0)
+++ trunk/LayoutTests/webgpu/whlsl-return-local-variable.html 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,131 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<canvas id="canvas" width="400" height="400"></canvas>
+<script>
+const shaderSource = `
+struct VertexOut {
+ float4 position : SV_Position;
+ float shade : attribute(0);
+}
+
+float copy(float v) {
+ float local = v;
+ return local;
+}
+
+vertex VertexOut vertexShader(float4 position : attribute(0), float shade : attribute(1)) {
+ VertexOut result;
+
+ result.position = position;
+ result.shade = copy(shade);
+
+ return result;
+}
+
+fragment float4 fragmentShader(float shade : attribute(0)) : SV_Target 0 {
+ return float4(shade, shade, shade, 1.0);
+}
+`;
+async function start() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+
+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true});
+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"};
+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"};
+ const primitiveTopology = "triangle-strip";
+ const rasterizationState = {frontFace: "cw", cullMode: "none"};
+ const alphaBlend = {};
+ const colorBlend = {};
+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL
+ const depthStencilState = null;
+
+ const attribute0 = {shaderLocation: 0, format: "float4"};
+ const attribute1 = {shaderLocation: 1, format: "float", offset: 16};
+ const attributes = [attribute0, attribute1];
+ const input0 = {stride: 20, attributeSet: attributes};
+ const inputs = [input0];
+ const vertexInput = {vertexBuffers: inputs};
+
+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]};
+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor);
+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]};
+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor);
+
+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout};
+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
+
+ const vertexBuffer0Descriptor = {size: Float32Array.BYTES_PER_ELEMENT * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE};
+ const vertexBuffer0 = device.createBuffer(vertexBuffer0Descriptor);
+ const vertexBuffer0ArrayBuffer = await vertexBuffer0.mapWriteAsync();
+ const vertexBuffer0Float32Array = new Float32Array(vertexBuffer0ArrayBuffer);
+ vertexBuffer0Float32Array[0] = -0.5;
+ vertexBuffer0Float32Array[1] = -0.5;
+ vertexBuffer0Float32Array[2] = 1.0;
+ vertexBuffer0Float32Array[3] = 1.0;
+ vertexBuffer0Float32Array[4] = 1.0;
+
+ vertexBuffer0Float32Array[5] = -0.5;
+ vertexBuffer0Float32Array[6] = 0.5;
+ vertexBuffer0Float32Array[7] = 1.0;
+ vertexBuffer0Float32Array[8] = 1.0;
+ vertexBuffer0Float32Array[9] = 1.0;
+
+ vertexBuffer0Float32Array[10] = 0.5;
+ vertexBuffer0Float32Array[11] = -0.5;
+ vertexBuffer0Float32Array[12] = 1.0;
+ vertexBuffer0Float32Array[13] = 1.0;
+ vertexBuffer0Float32Array[14] = 1.0;
+
+ vertexBuffer0Float32Array[15] = 0.5;
+ vertexBuffer0Float32Array[16] = 0.5;
+ vertexBuffer0Float32Array[17] = 1.0;
+ vertexBuffer0Float32Array[18] = 1.0;
+ vertexBuffer0Float32Array[19] = 1.0;
+ vertexBuffer0.unmap();
+
+ const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE};
+ const resourceBuffer = device.createBuffer(resourceBufferDescriptor);
+ const resourceBufferArrayBuffer = await resourceBuffer.mapWriteAsync();
+ const resourceBufferFloat32Array = new Float32Array(resourceBufferArrayBuffer);
+ resourceBufferFloat32Array[0] = 1;
+ resourceBuffer.unmap();
+
+ const bufferBinding = {buffer: resourceBuffer, size: 4};
+ const bindGroupBinding = {binding: 0, resource: bufferBinding};
+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]};
+ const bindGroup = device.createBindGroup(bindGroupDescriptor);
+
+ const canvas = document.getElementById("canvas");
+ const context = canvas.getContext("gpu");
+ const swapChainDescriptor = {device, format: "bgra8unorm"};
+ const swapChain = context.configureSwapChain(swapChainDescriptor);
+ const outputTexture = swapChain.getCurrentTexture();
+ const outputTextureView = outputTexture.createDefaultView();
+
+ const commandEncoder = device.createCommandEncoder(); // {}
+ const red = {r: 0, g: 0, b: 1, a: 1};
+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}];
+ const depthStencilAttachment = null;
+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment};
+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+ renderPassEncoder.setPipeline(renderPipeline);
+ renderPassEncoder.setBindGroup(0, bindGroup);
+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer0], [0]);
+ renderPassEncoder.draw(4, 1, 0, 0);
+ renderPassEncoder.endPass();
+ const commandBuffer = commandEncoder.finish();
+ device.getQueue().submit([commandBuffer]);
+
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+if (window.testRunner)
+ testRunner.waitUntilDone();
+window.addEventListener("load", start);
+</script>
+</body>
+</html>
Modified: trunk/Source/WTF/ChangeLog (245944 => 245945)
--- trunk/Source/WTF/ChangeLog 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WTF/ChangeLog 2019-05-31 04:31:54 UTC (rev 245945)
@@ -1,3 +1,13 @@
+2019-05-30 Saam Barati <[email protected]>
+
+ [WHLSL] Enforce variable lifetimes
+ https://bugs.webkit.org/show_bug.cgi?id=195794
+ <rdar://problem/50746293>
+
+ Reviewed by Myles C. Maxfield.
+
+ * wtf/PrintStream.h:
+
2019-05-30 Keith Rollin <[email protected]>
Fix yet more deprecated uses of -[UIApplication interfaceOrientation]
Modified: trunk/Source/WTF/wtf/PrintStream.h (245944 => 245945)
--- trunk/Source/WTF/wtf/PrintStream.h 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WTF/wtf/PrintStream.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -132,7 +132,7 @@
#define MAKE_PRINT_ADAPTOR(Name, Type, function) \
class Name { \
public: \
- Name(const Type& value) \
+ Name(Type value) \
: m_value(value) \
{ \
} \
Modified: trunk/Source/WebCore/ChangeLog (245944 => 245945)
--- trunk/Source/WebCore/ChangeLog 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/ChangeLog 2019-05-31 04:31:54 UTC (rev 245945)
@@ -1,3 +1,96 @@
+2019-05-30 Saam Barati <[email protected]>
+
+ [WHLSL] Enforce variable lifetimes
+ https://bugs.webkit.org/show_bug.cgi?id=195794
+ <rdar://problem/50746293>
+
+ Reviewed by Myles C. Maxfield.
+
+ In WHLSL, each variable has global lifetime. So returning a pointer to a
+ local variable is a legitimate and well specified thing to do. Each local
+ variable has a unique place in memory. So, for example:
+
+ ```
+ thread int* ptr() { int local; return &local; }
+ thread int* ptrPtr() { return ptr(); }
+ ```
+
+ In the above program, ptr() must always return the same value
+ as ptrPtr(). So, the following would print "42":
+ ```
+ thread int* p = ptrPtr();
+ *ptr() = 42;
+ print(*p);
+ ```
+
+ To implement these semantics, this patch introduces a new pass which does the
+ following transformations:
+ - It notes every variable whose address is taken in the program.
+ - Each such variable gets defined as a field in a struct.
+ - Each function which is an entry point defines this struct.
+ - Each non entry point takes a pointer to this struct as its final parameter.
+ - Each call to a non-native function is rewritten to pass a pointer to the
+ struct as the last call argument.
+ - Each variable reference to "x", where "x" ends up in the struct, is
+ modified to instead be "struct->x". We store to "struct->x" after declaring
+ "x". If "x" is a function parameter, we store to "struct->x" as the first
+ thing we do in the function body.
+
+ Tests: webgpu/whlsl-ensure-proper-variable-lifetime-2.html
+ webgpu/whlsl-ensure-proper-variable-lifetime-3.html
+ webgpu/whlsl-ensure-proper-variable-lifetime.html
+ webgpu/whlsl-return-local-variable.html
+
+ * Modules/webgpu/WHLSL/AST/WHLSLAST.h:
+ * Modules/webgpu/WHLSL/AST/WHLSLExpression.h:
+ (WebCore::WHLSL::AST::_expression_::_expression_):
+ (WebCore::WHLSL::AST::_expression_::isGlobalVariableReference const):
+ (WebCore::WHLSL::AST::_expression_::origin const): Deleted.
+ * Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h:
+ (WebCore::WHLSL::AST::FunctionDeclaration::origin):
+ * Modules/webgpu/WHLSL/AST/WHLSLGlobalVariableReference.h: Added.
+ (WebCore::WHLSL::AST::GlobalVariableReference::GlobalVariableReference):
+ (WebCore::WHLSL::AST::GlobalVariableReference::structField):
+ (WebCore::WHLSL::AST::GlobalVariableReference::base):
+ * Modules/webgpu/WHLSL/AST/WHLSLStatement.h:
+ (WebCore::WHLSL::AST::Statement::Statement):
+ (WebCore::WHLSL::AST::Statement::isStatementList const):
+ (WebCore::WHLSL::AST::Statement::isWhileLoop const):
+ * Modules/webgpu/WHLSL/AST/WHLSLStatementList.h: Added.
+ (WebCore::WHLSL::AST::StatementList::StatementList):
+ (WebCore::WHLSL::AST::StatementList::statements):
+ * Modules/webgpu/WHLSL/AST/WHLSLValue.h:
+ (WebCore::WHLSL::AST::Value::Value):
+ (WebCore::WHLSL::AST::Value::origin const):
+ * Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h:
+ (WebCore::WHLSL::AST::VariableDeclaration::VariableDeclaration):
+ (WebCore::WHLSL::AST::VariableDeclaration::takeInitializer):
+ (WebCore::WHLSL::AST::VariableDeclaration::origin const): Deleted.
+ * Modules/webgpu/WHLSL/AST/WHLSLVariableReference.h:
+ (WebCore::WHLSL::AST::VariableReference::wrap):
+ * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
+ * Modules/webgpu/WHLSL/WHLSLASTDumper.cpp:
+ (WebCore::WHLSL::ASTDumper::visit):
+ * Modules/webgpu/WHLSL/WHLSLASTDumper.h:
+ (WebCore::WHLSL::dumpASTNode):
+ (WebCore::WHLSL::dumpAST):
+ (WebCore::WHLSL::toString): Deleted.
+ * Modules/webgpu/WHLSL/WHLSLPrepare.cpp:
+ (WebCore::WHLSL::prepareShared):
+ * Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp: Added.
+ (WebCore::WHLSL::EscapedVariableCollector::takeEscapedVariables):
+ (WebCore::WHLSL::anonymousToken):
+ (WebCore::WHLSL::PreserveLifetimes::PreserveLifetimes):
+ (WebCore::WHLSL::PreserveLifetimes::makeStructVariableReference):
+ (WebCore::WHLSL::preserveVariableLifetimes):
+ * Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.h: Added.
+ * Modules/webgpu/WHLSL/WHLSLVisitor.cpp:
+ (WebCore::WHLSL::Visitor::visit):
+ * Modules/webgpu/WHLSL/WHLSLVisitor.h:
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+
2019-05-30 Ryan Haddad <[email protected]>
Unreviewed, rolling out r245890, 245887.
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAST.h (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAST.h 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLAST.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -57,6 +57,7 @@
#include "WHLSLFunctionAttribute.h"
#include "WHLSLFunctionDeclaration.h"
#include "WHLSLFunctionDefinition.h"
+#include "WHLSLGlobalVariableReference.h"
#include "WHLSLIfStatement.h"
#include "WHLSLIndexExpression.h"
#include "WHLSLIntegerLiteral.h"
@@ -84,6 +85,7 @@
#include "WHLSLSpecializationConstantSemantic.h"
#include "WHLSLStageInOutSemantic.h"
#include "WHLSLStatement.h"
+#include "WHLSLStatementList.h"
#include "WHLSLStructureDefinition.h"
#include "WHLSLStructureElement.h"
#include "WHLSLSwitchCase.h"
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLExpression.h (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLExpression.h 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLExpression.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -41,9 +41,10 @@
namespace AST {
class _expression_ : public Value {
+ using Base = Value;
public:
_expression_(Lexer::Token&& origin)
- : m_origin(WTFMove(origin))
+ : Base(WTFMove(origin))
{
}
@@ -55,8 +56,6 @@
_expression_& operator=(const _expression_&) = delete;
_expression_& operator=(_expression_&&) = default;
- const Lexer::Token& origin() const { return m_origin; }
-
UnnamedType* maybeResolvedType() { return m_type ? &*m_type : nullptr; }
UnnamedType& resolvedType()
@@ -91,6 +90,7 @@
virtual bool isCommaExpression() const { return false; }
virtual bool isDereferenceExpression() const { return false; }
virtual bool isDotExpression() const { return false; }
+ virtual bool isGlobalVariableReference() const { return false; }
virtual bool isFloatLiteral() const { return false; }
virtual bool isIndexExpression() const { return false; }
virtual bool isIntegerLiteral() const { return false; }
@@ -107,7 +107,6 @@
virtual bool isEnumerationMemberLiteral() const { return false; }
private:
- Lexer::Token m_origin;
Optional<UniqueRef<UnnamedType>> m_type;
Optional<TypeAnnotation> m_typeAnnotation;
};
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLFunctionDeclaration.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -76,6 +76,7 @@
VariableDeclarations& parameters() { return m_parameters; }
Optional<Semantic>& semantic() { return m_semantic; }
bool isOperator() const { return m_isOperator; }
+ Lexer::Token origin() { return m_origin; }
private:
Lexer::Token m_origin;
Copied: trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLGlobalVariableReference.h (from rev 245944, trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLValue.h) (0 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLGlobalVariableReference.h (rev 0)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLGlobalVariableReference.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBGPU)
+
+#include "WHLSLLexer.h"
+#include "WHLSLStructureElement.h"
+#include <wtf/UniqueRef.h>
+
+namespace WebCore {
+
+namespace WHLSL {
+
+namespace AST {
+
+class GlobalVariableReference : public _expression_ {
+public:
+ GlobalVariableReference(Lexer::Token&& origin, UniqueRef<_expression_>&& base, StructureElement* structField)
+ : _expression_(WTFMove(origin))
+ , m_base(WTFMove(base))
+ , m_structField(*structField)
+ {
+ ASSERT(structField);
+ }
+
+ virtual ~GlobalVariableReference() = default;
+ bool isGlobalVariableReference() const override { return true; }
+ StructureElement& structField() { return m_structField; }
+
+ _expression_& base() { return m_base.get(); }
+
+private:
+ UniqueRef<_expression_> m_base;
+ StructureElement& m_structField;
+};
+
+} // namespace AST
+
+}
+
+}
+
+SPECIALIZE_TYPE_TRAITS_WHLSL_EXPRESSION(GlobalVariableReference, isGlobalVariableReference())
+
+#endif
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLStatement.h (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLStatement.h 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLStatement.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -38,9 +38,10 @@
namespace AST {
class Statement : public Value {
+ using Base = Value;
public:
Statement(Lexer::Token&& origin)
- : m_origin(WTFMove(origin))
+ : Base(WTFMove(origin))
{
}
@@ -58,14 +59,12 @@
virtual bool isForLoop() const { return false; }
virtual bool isIfStatement() const { return false; }
virtual bool isReturn() const { return false; }
+ virtual bool isStatementList() const { return false; }
virtual bool isSwitchCase() const { return false; }
virtual bool isSwitchStatement() const { return false; }
virtual bool isTrap() const { return false; }
virtual bool isVariableDeclarationsStatement() const { return false; }
virtual bool isWhileLoop() const { return false; }
-
-private:
- Lexer::Token m_origin;
};
using Statements = Vector<UniqueRef<Statement>>;
Copied: trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLStatementList.h (from rev 245944, trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLValue.h) (0 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLStatementList.h (rev 0)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLStatementList.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBGPU)
+
+#include "WHLSLLexer.h"
+#include "WHLSLStatement.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+namespace WHLSL {
+
+namespace AST {
+
+class StatementList : public Statement {
+ using Base = Statement;
+public:
+ StatementList(Lexer::Token&& origin, Statements&& statements)
+ : Base(WTFMove(origin))
+ , m_statements(WTFMove(statements))
+ { }
+
+ virtual ~StatementList() = default;
+
+ Statements& statements() { return m_statements; }
+
+ bool isStatementList() const override { return true; }
+
+private:
+ Statements m_statements;
+};
+
+} // namespace AST
+
+}
+
+}
+
+SPECIALIZE_TYPE_TRAITS_WHLSL_STATEMENT(StatementList, isStatementList())
+
+#endif
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLValue.h (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLValue.h 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLValue.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -37,7 +37,8 @@
class Value : public Node {
public:
- Value()
+ Value(Lexer::Token&& origin)
+ : m_origin(WTFMove(origin))
{
}
@@ -49,7 +50,10 @@
Value& operator=(const Value&) = default;
Value& operator=(Value&&) = default;
-private:
+ Lexer::Token origin() const { return m_origin; }
+
+protected:
+ Lexer::Token m_origin;
};
} // namespace AST
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -45,9 +45,10 @@
namespace AST {
class VariableDeclaration : public Value {
+ using Base = Value;
public:
VariableDeclaration(Lexer::Token&& origin, Qualifiers&& qualifiers, Optional<UniqueRef<UnnamedType>>&& type, String&& name, Optional<Semantic>&& semantic, Optional<UniqueRef<_expression_>>&& initializer)
- : m_origin(WTFMove(origin))
+ : Base(WTFMove(origin))
, m_qualifiers(WTFMove(qualifiers))
, m_type(WTFMove(type))
, m_name(WTFMove(name))
@@ -61,7 +62,6 @@
VariableDeclaration(const VariableDeclaration&) = delete;
VariableDeclaration(VariableDeclaration&&) = default;
- const Lexer::Token& origin() const { return m_origin; }
String& name() { return m_name; }
const Optional<UniqueRef<UnnamedType>>& type() const { return m_type; } // Anonymous variables inside ReadModifyWriteExpressions have their type set by the type checker.
@@ -69,9 +69,9 @@
Optional<Semantic>& semantic() { return m_semantic; }
_expression_* initializer() { return m_initializer ? &*m_initializer : nullptr; }
bool isAnonymous() const { return m_name.isNull(); }
+ Optional<UniqueRef<_expression_>> takeInitializer() { return WTFMove(m_initializer); }
private:
- Lexer::Token m_origin;
Qualifiers m_qualifiers;
Optional<UniqueRef<UnnamedType>> m_type;
String m_name;
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableReference.h (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableReference.h 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableReference.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -55,6 +55,7 @@
{
VariableReference result(Lexer::Token(variableDeclaration.origin()));
result.m_variable = &variableDeclaration;
+ result.m_name = variableDeclaration.name();
return result;
}
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp 2019-05-31 04:31:54 UTC (rev 245945)
@@ -29,44 +29,11 @@
#if ENABLE(WEBGPU)
#include "NotImplemented.h"
-#include "WHLSLArrayReferenceType.h"
-#include "WHLSLArrayType.h"
-#include "WHLSLAssignmentExpression.h"
-#include "WHLSLBooleanLiteral.h"
-#include "WHLSLBuiltInSemantic.h"
-#include "WHLSLCallExpression.h"
-#include "WHLSLCommaExpression.h"
-#include "WHLSLDereferenceExpression.h"
-#include "WHLSLDoWhileLoop.h"
-#include "WHLSLEffectfulExpressionStatement.h"
-#include "WHLSLEntryPointScaffolding.h"
-#include "WHLSLEntryPointType.h"
-#include "WHLSLFloatLiteral.h"
-#include "WHLSLForLoop.h"
-#include "WHLSLFunctionDeclaration.h"
-#include "WHLSLFunctionDefinition.h"
-#include "WHLSLIfStatement.h"
-#include "WHLSLIntegerLiteral.h"
-#include "WHLSLLogicalExpression.h"
-#include "WHLSLLogicalNotExpression.h"
-#include "WHLSLMakeArrayReferenceExpression.h"
-#include "WHLSLMakePointerExpression.h"
-#include "WHLSLNativeFunctionDeclaration.h"
+#include "WHLSLAST.h"
#include "WHLSLNativeFunctionWriter.h"
-#include "WHLSLNativeTypeDeclaration.h"
-#include "WHLSLPointerType.h"
#include "WHLSLProgram.h"
-#include "WHLSLReturn.h"
-#include "WHLSLSwitchCase.h"
-#include "WHLSLSwitchStatement.h"
-#include "WHLSLTernaryExpression.h"
#include "WHLSLTypeNamer.h"
-#include "WHLSLUnsignedIntegerLiteral.h"
-#include "WHLSLVariableDeclaration.h"
-#include "WHLSLVariableDeclarationsStatement.h"
-#include "WHLSLVariableReference.h"
#include "WHLSLVisitor.h"
-#include "WHLSLWhileLoop.h"
#include <wtf/HashMap.h>
#include <wtf/text/StringBuilder.h>
@@ -156,6 +123,7 @@
void visit(AST::EnumerationMemberLiteral&) override;
void visit(AST::_expression_&) override;
void visit(AST::DotExpression&) override;
+ void visit(AST::GlobalVariableReference&) override;
void visit(AST::IndexExpression&) override;
void visit(AST::PropertyAccessExpression&) override;
void visit(AST::VariableDeclaration&) override;
@@ -446,6 +414,15 @@
m_stack.append("dummy");
}
+void FunctionDefinitionWriter::visit(AST::GlobalVariableReference& globalVariableReference)
+{
+ auto variableName = 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);
+}
+
void FunctionDefinitionWriter::visit(AST::IndexExpression&)
{
// This should be lowered already.
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.cpp (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.cpp 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.cpp 2019-05-31 04:31:54 UTC (rev 245945)
@@ -372,6 +372,17 @@
Base::visit(statement);
}
+void ASTDumper::visit(AST::StatementList& statementList)
+{
+ bool _once_ = false;
+ for (auto& statement : statementList.statements()) {
+ if (once)
+ m_out.print(";\n", m_indent);
+ _once_ = true;
+ visit(statement);
+ }
+}
+
void ASTDumper::visit(AST::Break&)
{
m_out.print("break");
@@ -441,6 +452,12 @@
m_out.print(".", dotExpression.fieldName());
}
+void ASTDumper::visit(AST::GlobalVariableReference& globalVariableReference)
+{
+ visit(globalVariableReference.base());
+ m_out.print("=>", globalVariableReference.structField().name());
+}
+
void ASTDumper::visit(AST::IndexExpression& indexExpression)
{
visit(static_cast<AST::PropertyAccessExpression&>(indexExpression));
@@ -529,7 +546,12 @@
visit(*variableDeclaration.type());
m_out.print(" ");
}
- m_out.print(variableDeclaration.name());
+
+ if (variableDeclaration.name().isEmpty())
+ m_out.print("$", RawPointer(&variableDeclaration));
+ else
+ m_out.print(variableDeclaration.name());
+
if (variableDeclaration.semantic())
visit(*variableDeclaration.semantic());
if (variableDeclaration.initializer()) {
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.h (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.h 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -44,7 +44,6 @@
String toString() { return m_out.toString(); }
-private:
void visit(AST::UnnamedType&) override;
void visit(AST::NamedType&) override;
void visit(AST::TypeDefinition&) override;
@@ -82,6 +81,7 @@
void visit(AST::FunctionAttribute&) override;
void visit(AST::NumThreadsFunctionAttribute&) override;
void visit(AST::Block&) override;
+ void visit(AST::StatementList&) override;
void visit(AST::Statement&) override;
void visit(AST::Break&) override;
void visit(AST::Continue&) override;
@@ -88,6 +88,7 @@
void visit(AST::DoWhileLoop&) override;
void visit(AST::_expression_&) override;
void visit(AST::DotExpression&) override;
+ void visit(AST::GlobalVariableReference&) override;
void visit(AST::IndexExpression&) override;
void visit(AST::PropertyAccessExpression&) override;
void visit(AST::EffectfulExpressionStatement&) override;
@@ -113,6 +114,7 @@
void visit(AST::TernaryExpression&) override;
void visit(AST::VariableReference&) override;
+private:
struct Indent {
Indent(ASTDumper& dumper)
: m_scope(dumper.m_indent, dumper.m_indent + " ")
@@ -128,16 +130,23 @@
String m_indent;
};
-static ALWAYS_INLINE String toString(Program& program)
+template <typename T>
+ALWAYS_INLINE void dumpASTNode(PrintStream& out, T& value)
{
ASTDumper dumper;
- dumper.visit(program);
- return dumper.toString();
+ dumper.visit(value);
+ out.print(dumper.toString());
}
+MAKE_PRINT_ADAPTOR(ExpressionDumper, AST::_expression_&, dumpASTNode);
+MAKE_PRINT_ADAPTOR(StatementDumper, AST::Statement&, dumpASTNode);
+MAKE_PRINT_ADAPTOR(ProgramDumper, Program&, dumpASTNode);
+MAKE_PRINT_ADAPTOR(StructureDefinitionDumper, AST::StructureDefinition&, dumpASTNode);
+MAKE_PRINT_ADAPTOR(FunctionDefinitionDumper, AST::FunctionDefinition&, dumpASTNode);
+
static ALWAYS_INLINE void dumpAST(Program& program)
{
- dataLogLn(toString(program));
+ dataLogLn(ProgramDumper(program));
}
} // namespace WHLSL
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp 2019-05-31 04:31:54 UTC (rev 245945)
@@ -37,6 +37,7 @@
#include "WHLSLMetalCodeGenerator.h"
#include "WHLSLNameResolver.h"
#include "WHLSLParser.h"
+#include "WHLSLPreserveVariableLifetimes.h"
#include "WHLSLProgram.h"
#include "WHLSLPropertyResolver.h"
#include "WHLSLRecursionChecker.h"
@@ -56,7 +57,9 @@
static constexpr bool dumpASTBeforeEachPass = false;
static constexpr bool dumpASTAfterParsing = false;
-static constexpr bool dumpASTAtEnd = false;
+static constexpr bool dumpASTAtEnd = true;
+static constexpr bool alwaysDumpPassFailures = false;
+static constexpr bool dumpPassFailure = dumpASTBeforeEachPass || dumpASTAfterParsing || dumpASTAtEnd || alwaysDumpPassFailures;
static bool dumpASTIfNeeded(bool shouldDump, Program& program, const char* message)
{
@@ -87,8 +90,11 @@
#define RUN_PASS(pass, ...) \
do { \
dumpASTBetweenEachPassIfNeeded(program, "AST before " # pass); \
- if (!pass(__VA_ARGS__)) \
+ if (!pass(__VA_ARGS__)) { \
+ if (dumpPassFailure) \
+ dataLogLn("failed pass: " # pass); \
return WTF::nullopt; \
+ } \
} while (0)
@@ -123,6 +129,7 @@
RUN_PASS(checkStatementBehavior, program);
RUN_PASS(checkRecursion, program);
RUN_PASS(checkFunctionStages, program);
+ preserveVariableLifetimes(program);
dumpASTAtEndIfNeeded(program);
Added: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp (0 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp (rev 0)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WHLSLPreserveVariableLifetimes.h"
+
+#if ENABLE(WEBGPU)
+
+#include "WHLSLAST.h"
+#include "WHLSLASTDumper.h"
+#include "WHLSLVisitor.h"
+
+namespace WebCore {
+
+namespace WHLSL {
+
+// This pass works by ensuring proper variable lifetimes. In WHLSL, each variable
+// has global lifetime. So returning a pointer to a local variable is a totally
+// legitimate and well-specified thing to do.
+//
+// We implement this by:
+// - We note every variable whose address we take.
+// - Each such variable gets defined as a field in a struct.
+// - Each function which is an entry point defines this struct.
+// - Each non entry point takes a pointer to this struct as its final parameter.
+// - Each call to a non-native function is rewritten to pass a pointer to the
+// struct as the last call argument.
+// - Each variable reference to "x", where "x" ends up in the struct, is
+// modified to instead be "struct->x". We store to "struct->x" after declaring
+// "x". If "x" is a function parameter, we store to "struct->x" as the first
+// thing we do in the function body.
+
+class EscapedVariableCollector : public Visitor {
+ using Base = Visitor;
+public:
+ void visit(AST::MakePointerExpression& makePointerExpression) override
+ {
+ if (!is<AST::VariableReference>(makePointerExpression.leftValue())) {
+ // FIXME: Are we missing any interesting productions here?
+ // https://bugs.webkit.org/show_bug.cgi?id=198311
+ Base::visit(makePointerExpression.leftValue());
+ return;
+ }
+
+ auto& variableReference = downcast<AST::VariableReference>(makePointerExpression.leftValue());
+ auto* variable = variableReference.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:
+ // https://bugs.webkit.org/show_bug.cgi?id=198383
+ m_escapedVariables.add(variable, makeString("_", variable->name(), "_", m_count++));
+ }
+
+ HashMap<AST::VariableDeclaration*, String> takeEscapedVariables() { return WTFMove(m_escapedVariables); }
+
+private:
+ size_t m_count { 1 };
+ HashMap<AST::VariableDeclaration*, String> m_escapedVariables;
+};
+
+static ALWAYS_INLINE Lexer::Token anonymousToken(Lexer::Token::Type type)
+{
+ return Lexer::Token { { }, 0, type };
+}
+
+class PreserveLifetimes : public Visitor {
+ using Base = Visitor;
+public:
+ PreserveLifetimes(UniqueRef<AST::TypeReference>& structType, const HashMap<AST::VariableDeclaration*, AST::StructureElement*>& variableMapping)
+ : m_structType(structType)
+ , m_pointerToStructType(makeUniqueRef<AST::PointerType>(anonymousToken(Lexer::Token::Type::Identifier), AST::AddressSpace::Thread, m_structType->clone()))
+ , m_variableMapping(variableMapping)
+ { }
+
+ UniqueRef<AST::VariableReference> makeStructVariableReference()
+ {
+ auto structVariableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(*m_structVariable));
+ structVariableReference->setType(m_structVariable->type()->clone());
+ structVariableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread });
+ return structVariableReference;
+ }
+
+ UniqueRef<AST::AssignmentExpression> assignVariableIntoStruct(AST::VariableDeclaration& variable, AST::StructureElement* element)
+ {
+ auto lhs = makeUniqueRef<AST::GlobalVariableReference>(variable.origin(), makeStructVariableReference(), element);
+ lhs->setType(variable.type()->clone());
+ lhs->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread });
+
+ auto rhs = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variable));
+ rhs->setType(variable.type()->clone());
+ rhs->setTypeAnnotation(AST::RightValue());
+
+ auto assignment = makeUniqueRef<AST::AssignmentExpression>(variable.origin(), WTFMove(lhs), WTFMove(rhs));
+ assignment->setType(variable.type()->clone());
+ assignment->setTypeAnnotation(AST::RightValue());
+
+ return assignment;
+ }
+
+ void visit(AST::FunctionDefinition& functionDefinition) override
+ {
+ bool isEntryPoint = !!functionDefinition.entryPointType();
+ if (isEntryPoint) {
+ auto structVariableDeclaration = makeUniqueRef<AST::VariableDeclaration>(functionDefinition.origin(), AST::Qualifiers(),
+ m_structType->clone(), String(), WTF::nullopt, WTF::nullopt);
+
+ auto structVariableReference = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(structVariableDeclaration));
+ structVariableReference->setType(m_structType->clone());
+ structVariableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread });
+
+ AST::VariableDeclarations structVariableDeclarations;
+ structVariableDeclarations.append(WTFMove(structVariableDeclaration));
+ auto structDeclarationStatement = makeUniqueRef<AST::VariableDeclarationsStatement>(functionDefinition.origin(), WTFMove(structVariableDeclarations));
+
+ auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(functionDefinition.origin(), WTFMove(structVariableReference));
+ makePointerExpression->setType(m_pointerToStructType->clone());
+ makePointerExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread });
+
+ auto pointerDeclaration = makeUniqueRef<AST::VariableDeclaration>(functionDefinition.origin(), AST::Qualifiers(),
+ m_pointerToStructType->clone(), "wrapper"_s, WTF::nullopt, Optional<UniqueRef<AST::_expression_>>(WTFMove(makePointerExpression)));
+ m_structVariable = &pointerDeclaration;
+
+ AST::VariableDeclarations pointerVariableDeclarations;
+ pointerVariableDeclarations.append(WTFMove(pointerDeclaration));
+ auto pointerDeclarationStatement = makeUniqueRef<AST::VariableDeclarationsStatement>(functionDefinition.origin(), WTFMove(pointerVariableDeclarations));
+
+ functionDefinition.block().statements().insert(0, WTFMove(structDeclarationStatement));
+ functionDefinition.block().statements().insert(1, WTFMove(pointerDeclarationStatement));
+ } else {
+ auto pointerDeclaration = makeUniqueRef<AST::VariableDeclaration>(functionDefinition.origin(), AST::Qualifiers(),
+ m_pointerToStructType->clone(), "wrapper"_s, WTF::nullopt, WTF::nullopt);
+ m_structVariable = &pointerDeclaration;
+ functionDefinition.parameters().append(WTFMove(pointerDeclaration));
+ }
+
+ Base::visit(functionDefinition);
+
+ for (auto& parameter : functionDefinition.parameters()) {
+ auto iter = m_variableMapping.find(¶meter);
+ if (iter == m_variableMapping.end())
+ continue;
+
+ functionDefinition.block().statements().insert(isEntryPoint ? 2 : 0,
+ makeUniqueRef<AST::EffectfulExpressionStatement>(assignVariableIntoStruct(parameter, iter->value)));
+ }
+
+ // Inner functions are not allowed in WHLSL. So this is fine.
+ m_structVariable = nullptr;
+ }
+
+ void visit(AST::CallExpression& callExpression) override
+ {
+ RELEASE_ASSERT(m_structVariable);
+
+ Base::visit(callExpression);
+
+ // This works because it's illegal to call an entrypoint. Therefore, we can only
+ // call functions where we've already appended this struct as its final parameter.
+ if (!callExpression.function()->isNativeFunctionDeclaration())
+ callExpression.arguments().append(makeStructVariableReference());
+ }
+
+ void visit(AST::VariableReference& variableReference) override
+ {
+ RELEASE_ASSERT(m_structVariable);
+
+ auto iter = m_variableMapping.find(variableReference.variable());
+ if (iter == m_variableMapping.end())
+ return;
+
+ auto type = variableReference.variable()->type()->clone();
+ AST::TypeAnnotation typeAnnotation = variableReference.typeAnnotation();
+ auto* internalField = AST::replaceWith<AST::GlobalVariableReference>(variableReference, variableReference.origin(), makeStructVariableReference(), iter->value);
+ internalField->setType(WTFMove(type));
+ internalField->setTypeAnnotation(WTFMove(typeAnnotation));
+ }
+
+ void visit(AST::VariableDeclarationsStatement& variableDeclarationsStatement) override
+ {
+ RELEASE_ASSERT(m_structVariable);
+
+ Base::visit(variableDeclarationsStatement);
+
+ AST::Statements statements;
+ for (UniqueRef<AST::VariableDeclaration>& variableDeclaration : variableDeclarationsStatement.variableDeclarations()) {
+ AST::VariableDeclaration& variable = variableDeclaration.get();
+
+ {
+ AST::VariableDeclarations declarations;
+ declarations.append(WTFMove(variableDeclaration));
+ statements.append(makeUniqueRef<AST::VariableDeclarationsStatement>(variable.origin(), WTFMove(declarations)));
+ }
+
+ auto iter = m_variableMapping.find(&variable);
+ if (iter != m_variableMapping.end())
+ statements.append(makeUniqueRef<AST::EffectfulExpressionStatement>(assignVariableIntoStruct(variable, iter->value)));
+ }
+
+ auto origin = Lexer::Token(variableDeclarationsStatement.origin());
+ AST::replaceWith<AST::StatementList>(variableDeclarationsStatement, WTFMove(origin), WTFMove(statements));
+ }
+
+private:
+ AST::VariableDeclaration* m_structVariable { nullptr };
+
+ UniqueRef<AST::TypeReference>& m_structType;
+ UniqueRef<AST::PointerType> m_pointerToStructType;
+ // If this mapping contains the variable, it means that the variable's canonical location
+ // is in the struct we use to preserve variable lifetimes.
+ const HashMap<AST::VariableDeclaration*, AST::StructureElement*>& m_variableMapping;
+};
+
+void preserveVariableLifetimes(Program& program)
+{
+ HashMap<AST::VariableDeclaration*, String> escapedVariables;
+ {
+ EscapedVariableCollector collector;
+ collector.Visitor::visit(program);
+ escapedVariables = collector.takeEscapedVariables();
+ }
+
+ AST::StructureElements elements;
+ for (auto& pair : escapedVariables) {
+ auto* variable = pair.key;
+ String name = pair.value;
+ elements.append(AST::StructureElement { Lexer::Token(variable->origin()), { }, variable->type()->clone(), WTFMove(name), WTF::nullopt });
+ }
+
+ // Name of this doesn't matter, since we don't use struct names when
+ // generating Metal type names. We just pick something here to make it
+ // easy to read in AST dumps.
+ auto wrapperStructDefinition = makeUniqueRef<AST::StructureDefinition>(anonymousToken(Lexer::Token::Type::Struct), "__WrapperStruct__"_s, WTFMove(elements));
+
+ HashMap<AST::VariableDeclaration*, AST::StructureElement*> variableMapping;
+ unsigned index = 0;
+ for (auto& pair : escapedVariables)
+ variableMapping.add(pair.key, &wrapperStructDefinition->structureElements()[index++]);
+
+ {
+ auto wrapperStructType = AST::TypeReference::wrap(anonymousToken(Lexer::Token::Type::Identifier), wrapperStructDefinition);
+ PreserveLifetimes preserveLifetimes(wrapperStructType, variableMapping);
+ preserveLifetimes.Visitor::visit(program);
+ }
+
+ program.structureDefinitions().append(WTFMove(wrapperStructDefinition));
+}
+
+} // namespace WHLSL
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGPU)
Copied: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.h (from rev 245944, trunk/Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLValue.h) (0 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.h (rev 0)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBGPU)
+
+namespace WebCore {
+
+namespace WHLSL {
+
+class Program;
+
+void preserveVariableLifetimes(Program&);
+
+}
+
+}
+
+#endif
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.cpp (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.cpp 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.cpp 2019-05-31 04:31:54 UTC (rev 245945)
@@ -300,6 +300,12 @@
checkErrorAndVisit(statement);
}
+void Visitor::visit(AST::StatementList& statementList)
+{
+ for (auto& statement : statementList.statements())
+ checkErrorAndVisit(statement);
+}
+
void Visitor::visit(AST::Statement& statement)
{
if (is<AST::Block>(statement))
@@ -320,6 +326,8 @@
checkErrorAndVisit(downcast<AST::IfStatement>(statement));
else if (is<AST::Return>(statement))
checkErrorAndVisit(downcast<AST::Return>(statement));
+ else if (is<AST::StatementList>(statement))
+ checkErrorAndVisit(downcast<AST::StatementList>(statement));
else if (is<AST::SwitchCase>(statement))
checkErrorAndVisit(downcast<AST::SwitchCase>(statement));
else if (is<AST::SwitchStatement>(statement))
@@ -376,6 +384,8 @@
checkErrorAndVisit(downcast<AST::NullLiteral>(_expression_));
else if (is<AST::DotExpression>(_expression_))
checkErrorAndVisit(downcast<AST::DotExpression>(_expression_));
+ else if (is<AST::GlobalVariableReference>(_expression_))
+ checkErrorAndVisit(downcast<AST::GlobalVariableReference>(_expression_));
else if (is<AST::IndexExpression>(_expression_))
checkErrorAndVisit(downcast<AST::IndexExpression>(_expression_));
else if (is<AST::ReadModifyWriteExpression>(_expression_))
@@ -397,6 +407,11 @@
checkErrorAndVisit(static_cast<AST::PropertyAccessExpression&>(dotExpression));
}
+void Visitor::visit(AST::GlobalVariableReference& globalVariableReference)
+{
+ checkErrorAndVisit(globalVariableReference.base());
+}
+
void Visitor::visit(AST::IndexExpression& indexExpression)
{
checkErrorAndVisit(indexExpression.indexExpression());
Modified: trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.h (245944 => 245945)
--- trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.h 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLVisitor.h 2019-05-31 04:31:54 UTC (rev 245945)
@@ -66,6 +66,7 @@
class EnumerationMemberLiteral;
class NumThreadsFunctionAttribute;
class Block;
+class StatementList;
class Statement;
class Break;
class Continue;
@@ -72,6 +73,7 @@
class DoWhileLoop;
class _expression_;
class DotExpression;
+class GlobalVariableReference;
class IndexExpression;
class PropertyAccessExpression;
class EffectfulExpressionStatement;
@@ -145,6 +147,7 @@
virtual void visit(AST::FunctionAttribute&);
virtual void visit(AST::NumThreadsFunctionAttribute&);
virtual void visit(AST::Block&);
+ virtual void visit(AST::StatementList&);
virtual void visit(AST::Statement&);
virtual void visit(AST::Break&);
virtual void visit(AST::Continue&);
@@ -151,6 +154,7 @@
virtual void visit(AST::DoWhileLoop&);
virtual void visit(AST::_expression_&);
virtual void visit(AST::DotExpression&);
+ virtual void visit(AST::GlobalVariableReference&);
virtual void visit(AST::IndexExpression&);
virtual void visit(AST::PropertyAccessExpression&);
virtual void visit(AST::EffectfulExpressionStatement&);
Modified: trunk/Source/WebCore/Sources.txt (245944 => 245945)
--- trunk/Source/WebCore/Sources.txt 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/Sources.txt 2019-05-31 04:31:54 UTC (rev 245945)
@@ -322,6 +322,7 @@
Modules/webgpu/WHLSL/WHLSLStatementBehaviorChecker.cpp
Modules/webgpu/WHLSL/WHLSLNameContext.cpp
Modules/webgpu/WHLSL/WHLSLNameResolver.cpp
+Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp
Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp
Modules/webgpu/WHLSL/WHLSLRecursionChecker.cpp
Modules/webgpu/WHLSL/WHLSLVisitor.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (245944 => 245945)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-05-31 03:14:35 UTC (rev 245944)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-05-31 04:31:54 UTC (rev 245945)
@@ -8336,6 +8336,9 @@
51FB67DA1AE6B5E400D06C5A /* ContentExtensionStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentExtensionStyleSheet.h; sourceTree = "<group>"; };
52131E5A1C4F15610033F802 /* VideoFullscreenInterfaceMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = VideoFullscreenInterfaceMac.mm; sourceTree = "<group>"; };
5215862C229377B7005925EF /* WHLSLAST.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLAST.h; sourceTree = "<group>"; };
+ 522DA3D3229E1D390042D151 /* WHLSLGlobalVariableReference.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLGlobalVariableReference.h; sourceTree = "<group>"; };
+ 522E1A172297D6D400E5D36A /* WHLSLPreserveVariableLifetimes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLPreserveVariableLifetimes.cpp; sourceTree = "<group>"; };
+ 522E1A192297D6D400E5D36A /* WHLSLPreserveVariableLifetimes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLPreserveVariableLifetimes.h; sourceTree = "<group>"; };
526724F11CB2FDF60075974D /* TextTrackRepresentationCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TextTrackRepresentationCocoa.mm; sourceTree = "<group>"; };
526724F21CB2FDF60075974D /* TextTrackRepresentationCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextTrackRepresentationCocoa.h; sourceTree = "<group>"; };
52B0D4BD1C57FD1E0077CE53 /* PlatformView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformView.h; sourceTree = "<group>"; };
@@ -17068,6 +17071,7 @@
C21BF70521CD89C700227979 /* WHLSLFunctionAttribute.h */,
C21BF6FD21CD89C000227979 /* WHLSLFunctionDeclaration.h */,
C21BF6F421CD89B300227979 /* WHLSLFunctionDefinition.h */,
+ 522DA3D3229E1D390042D151 /* WHLSLGlobalVariableReference.h */,
C21BF6FF21CD89C200227979 /* WHLSLIfStatement.h */,
C21BF6F721CD89B900227979 /* WHLSLIndexExpression.h */,
C20F4F6621DFF2360070C45A /* WHLSLIntegerLiteral.cpp */,
@@ -25455,6 +25459,8 @@
C24A57AF21FAD53F004C6DD1 /* WHLSLPipelineDescriptor.h */,
C24A57BA21FEAFEA004C6DD1 /* WHLSLPrepare.cpp */,
C24A57BB21FEAFEA004C6DD1 /* WHLSLPrepare.h */,
+ 522E1A172297D6D400E5D36A /* WHLSLPreserveVariableLifetimes.cpp */,
+ 522E1A192297D6D400E5D36A /* WHLSLPreserveVariableLifetimes.h */,
C21BF73A21CD8D7000227979 /* WHLSLProgram.h */,
1CAA82F62242AE0500E84BBB /* WHLSLPropertyResolver.cpp */,
1CAA82F72242AE0500E84BBB /* WHLSLPropertyResolver.h */,